#include <vcl.h>
#pragma hdrstop

USEPACKAGE("EIC.bpi");
USEPACKAGE("EICBtrv.bpi");
USEPACKAGE("Outils.bpi");
USEPACKAGE("CtrlStd.bpi");
USEPACKAGE("CtrlDB.bpi");
USERES("Compta.dcr");
USERC("Compta.rc");
USERC("Version.rc");
USE("Compta.h", File);
USEFORM("uCrMoCpt.cpp", dlgModCreCpt);
USEFORM("uCrMoJnl.cpp", dlgModCreJnl);
USEFORM("uLetAuto.cpp", frmLettrageAuto);
USEPACKAGE("vcl50.bpi");
USEPACKAGE("vclx50.bpi");
USEPACKAGE("vcldb50.bpi");
USEPACKAGE("vclbde50.bpi");
USEUNIT("CPosteDLL.cpp");
USEUNIT("CCompDLL.cpp");
USEUNIT("CExtraDLL.cpp");
USEFORM("uSelJnl.cpp", dlgSelectJnl);
USEPACKAGE("VCLIB50.bpi");
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "CTable"

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
    return 1;
}
//---------------------------------------------------------------------------


#ifdef _DEBUG
  #pragma message *** VERSION DEBUG EN DUR DU PAQUET Compta ***
#endif
#include <VCL\VCL.h>
#include <EIC.h>
#pragma hdrstop

#include <stdlib.h>

#include "Compta.h"
#include "uCrMoJnl.h"
#include "uCrMoCpt.h"
#include "Compta.hrc"
#include "CMForm.h"
#include "uSelJnl.h"
#include <vector>

#define MODULE_TAG 1000
#pragma option -d // Le compilateur fusionne les chaînes dupliquées

namespace Compta
{
 const char *_strPtInterro = "?";
 static UINT    _uMsgResultatDate    = ::RegisterWindowMessage( STR_MESSAGE_RESULTAT_DATE);
 static UINT    _uMsgResultatMontant = ::RegisterWindowMessage( STR_MESSAGE_RESULTAT_MONTANT);

 bool           cm_bEstMenufedEntreprise;

const DEF_MODE_PAIEMENT LISTE_MODE_PAIEMENT[MAX_MODE_PAIEMT] = {
                  { MP_ESPECES           , TL_ACHATS | TL_VENTES | TL_ENCAISSEMENT | TL_DECAISSEMENT | TL_TOUS, "ESP" , "Espèces"                                     },
                  { MP_CHEQUE            , TL_ACHATS | TL_VENTES | TL_ENCAISSEMENT | TL_DECAISSEMENT | TL_TOUS, "CHQ" , "Chèque"                                      },
                  { MP_CARTEBANCAIRE     , TL_ACHATS | TL_VENTES | TL_ENCAISSEMENT | TL_DECAISSEMENT | TL_TOUS, "CB"  , "Carte bancaire"                              },
                  { MP_VIREMENT          , TL_ACHATS | TL_VENTES | TL_ENCAISSEMENT | TL_DECAISSEMENT | TL_TOUS, "VIR" , "Virement"                                    },
                  { MP_PRELEVEMENT       , TL_ACHATS | TL_VENTES | TL_ENCAISSEMENT | TL_DECAISSEMENT | TL_TOUS, "PRE" , "Prélèvement"                                 },
                  { MP_EFFETCOM_RECEPTION,                         TL_ENCAISSEMENT | TL_DECAISSEMENT | TL_TOUS, "EFF" , "Effet de commerce (réception/paiement)"      },
                  { MP_EFFETCOM_ESCOMPTE ,                         TL_ENCAISSEMENT                   | TL_TOUS, "ESC" , "Effet de commerce (remise à l'escompte)"     },
                  { MP_EFFETCOM_ENCAIS   ,                         TL_ENCAISSEMENT                   | TL_TOUS, "ENC" , "Effet de commerce (remise à l'encaissement)" },
                  { MP_TITRERESTO        , TL_ACHATS | TL_VENTES | TL_ENCAISSEMENT                   | TL_TOUS, "RES" , "Titre-restaurant"                            },
                  { MP_CHEQUEVANCANCES   , TL_ACHATS | TL_VENTES | TL_ENCAISSEMENT                   | TL_TOUS, "VAC" , "Chèque vacances"                             },
                  { MP_TIP               , TL_ACHATS                               | TL_DECAISSEMENT | TL_TOUS, "TIP" , "T.I.P."                                      },
                  { MP_COMPENSATION      , TL_ACHATS | TL_VENTES | TL_ENCAISSEMENT | TL_DECAISSEMENT | TL_TOUS, "CMP" , "Compensation"                                },
                  { MP_BILLET_ORDRE_REL  , TL_ACHATS | TL_VENTES                                     | TL_TOUS, "BOR" , "Billet à ordre relevé"                       },
                  { MP_LETTRE_CHANGE_REL , TL_ACHATS | TL_VENTES                                     | TL_TOUS, "LCR" , "Lettre de change relevé"                     },
                  { MP_VIREMENT_TRESO    ,                                                             TL_TOUS, "VSOT", "Virement spécifique orienté trésorerie"      },
                  { MP_TELEREGL_INTERNET ,                         TL_ENCAISSEMENT | TL_DECAISSEMENT | TL_TOUS, "TEP" , "Télérèglement par internet"                  },
                  { MP_BILLET_ORDRE      , TL_ACHATS | TL_VENTES                                     | TL_TOUS, "BO"  , "Billet à ordre"                              },
                  { MP_LETTRE_CHANGE     , TL_ACHATS | TL_VENTES                                     | TL_TOUS, "LC"  , "Lettre de change"                            }};

 void __fastcall PACKAGE Register()
 {
   TComponentClass classes[] = { __classid(TTableJnx),
                                 __classid(TTablePC),
                                 __classid(TTableHI), __classid(TTableHITmp),
                                 __classid(TTablePT)
                               };

   RegisterComponents("EIC Compta", classes, ARRAYSIZE(classes) - 1);
 }


 //*******************************************//
 // Définition des noms des champs des tables //
 //*******************************************//
 // Journaux
 const AnsiString TTableJnx::strfJN_Code(                 szfJN_Code);
 const AnsiString TTableJnx::strfJN_Intitule(             szfJN_Intitule);
 const AnsiString TTableJnx::strfJN_Nature(               szfJN_Nature);
 const AnsiString TTableJnx::strfJN_Flags(                szfJN_Flags);
 const AnsiString TTableJnx::strfJN_ModalitesSaisie(      szfJN_ModalitesSaisie);
 const AnsiString TTableJnx::strfJN_CompteContrepartie(   szfJN_CompteContrepartie);
 const AnsiString TTableJnx::strfJN_EncaisModSaisie(      szfJN_EncaisModSaisie);
 const AnsiString TTableJnx::strfJN_EncaisCptTreso(       szfJN_EncaisCptTreso);
 const AnsiString TTableJnx::strfJN_DeviseDefClassique(   szfJN_DeviseDefClassique);
 const AnsiString TTableJnx::strfJN_DeviseDefEncais(      szfJN_DeviseDefEncais);
 const AnsiString TTableJnx::strfJN_CodeOrigine(          szfJN_CodeOrigine);
 const AnsiString TTableJnx::strfJN_AchVntModalSais(      szfJN_AchVntModalSais);
 const AnsiString TTableJnx::strfJN_AchVntLibelle(        szfJN_AchVntLibelle);
 const AnsiString TTableJnx::strfJN_AchVntDeviseDefaut(   szfJN_AchVntDeviseDefaut);
 const AnsiString TTableJnx::strfJN_AchVntModePaiement(   szfJN_AchVntModePaiement);
 const AnsiString TTableJnx::strfJN_AchVntCptTVA_biens(   szfJN_AchVntCptTVA_biens);
 const AnsiString TTableJnx::strfJN_AchVntCptTVA_immo(    szfJN_AchVntCptTVA_immo);
 const AnsiString TTableJnx::strfJN_AchVntCptTVA_col(     szfJN_AchVntCptTVA_col);
 const AnsiString TTableJnx::strfJN_AchVntBanquePaiement( szfJN_AchVntBanquePaiement);
 const AnsiString TTableJnx::strfJN_AchVntDateEchJour(    szfJN_AchVntDateEchJour);
 const AnsiString TTableJnx::strfJN_AchVntDateEchMode(    szfJN_AchVntDateEchMode);
 const AnsiString TTableJnx::strfJN_AchVntDateEchLe(      szfJN_AchVntDateEchLe);
 const AnsiString TTableJnx::strfJN_KmModalSais(          szfJN_KmModalSais);
 const AnsiString TTableJnx::strfJN_KmDeviseDefaut(       szfJN_KmDeviseDefaut);
 const AnsiString TTableJnx::strfJN_KmDeviseCompte(       szfJN_KmDeviseCompte);
 const AnsiString TTableJnx::strfJN_KmTauxFixe(           szfJN_KmTauxFixe);
 const AnsiString TTableJnx::strfJN_AchVntDematModalSais( szfJN_AchVntDematModalSais);

 bool TTableJnx::VoirJournauxInventaires = true;
 bool TTableJnx::CocheOCRpourJournauxAchat;
 bool TTableJnx::CocheOCRpourJournauxVente;

 // Historique
 const AnsiString TTableHI::strfHI_DateImputation(  szfHI_DateImputation);
 const AnsiString TTableHI::strfHI_AutoID(          szfHI_AutoID);
 const AnsiString TTableHI::strfHI_Compte(          szfHI_Compte);
 const AnsiString TTableHI::strfHI_CodeJournal(     szfHI_CodeJournal);
 const AnsiString TTableHI::strfHI_RANDateOrigine(  szfHI_RANDateOrigine);
 const AnsiString TTableHI::strfHI_RANJnlOrigine(   szfHI_RANJnlOrigine);
 const AnsiString TTableHI::strfHI_Piece(           szfHI_Piece);
 const AnsiString TTableHI::strfHI_PieceExterne(    szfHI_PieceExterne);
 const AnsiString TTableHI::strfHI_NaturePiece(     szfHI_NaturePiece);
 const AnsiString TTableHI::strfHI_PieceLiee(       szfHI_PieceLiee);
 const AnsiString TTableHI::strfHI_Lettrage(        szfHI_Lettrage);
 const AnsiString TTableHI::strfHI_FlagLettrage(    szfHI_FlagLettrage);
 const AnsiString TTableHI::strfHI_IDEcriture(      szfHI_IDEcriture);
 const AnsiString TTableHI::strfHI_IDEcriturePart(  szfHI_IDEcriturePart);
 const AnsiString TTableHI::strfHI_LibelleOperation(szfHI_LibelleOperation);
 const AnsiString TTableHI::strfHI_MontantOrigine(  szfHI_MontantOrigine);
 const AnsiString TTableHI::strfHI_CodeDevise(      szfHI_CodeDevise);
 const AnsiString TTableHI::strfHI_TauxChange(      szfHI_TauxChange);
 const AnsiString TTableHI::strfHI_Montant(         szfHI_Montant);
 const AnsiString TTableHI::strfHI_EstCrediteur(    szfHI_EstCrediteur);
 const AnsiString TTableHI::strfHI_DateEcheance(    szfHI_DateEcheance);
 const AnsiString TTableHI::strfHI_RAOData(         szfHI_RAOData);
 const AnsiString TTableHI::strfHI_DateDebPeriode(  szfHI_DateDebPeriode);
 const AnsiString TTableHI::strfHI_DateFinPeriode(  szfHI_DateFinPeriode);
 const AnsiString TTableHI::strfHI_RAOIDLigne(      szfHI_RAOIDLigne);
 const AnsiString TTableHI::strfHI_Flags(           szfHI_Flags);
 const AnsiString TTableHI::strfHI_IDImage(         szfHI_IDImage);
 const AnsiString TTableHI::strfHI_Designation(     szfHI_Designation);
 const AnsiString TTableHI::strfHI_CodeTVA(         szfHI_CodeTVA);
 const AnsiString TTableHI::strfHI_TauxTVA(         szfHI_TauxTVA);
 const AnsiString TTableHI::strfHI_ModePaiement(    szfHI_ModePaiement);
 const AnsiString TTableHI::strfHI_Banque(          szfHI_Banque);
 const AnsiString TTableHI::strfHI_Quantite(        szfHI_Quantite);
 const AnsiString TTableHI::strfHI_CodeAnalytik(    szfHI_CodeAnalytik);
 const AnsiString TTableHI::strfHI_DateEP(          szfHI_DateEP);
 const AnsiString TTableHI::strfHI_Reviseur(        szfHI_Reviseur);
 const AnsiString TTableHI::strfHI_Reference(       szfHI_Reference);
 const AnsiString TTableHI::strfHI_DateExport(      szfHI_DateExport);

 CTable        *TTableHI::m_pTable         = NULL;
 TIntegerField *TTableHI::m_pfldIDMaster   = NULL;
 TIntegerField *TTableHI::m_pfldIDInc      = NULL;
 int        TTableHI::m_nCountInstance     =  0;
 int        TTableHI::m_nReviseur          =  0;
 void __fastcall ( *TTableHI::m_fncAccepterEcriture)( const TDateTime&) = NULL;
 AnsiString TTableHI::m_strCompteALettrer;
 int TTableHI::m_nRecurs;
 TfrmLettrageAuto *TTableHI::m_frmLettrageAuto = NULL;
 TList *TTableHI::m_pSoluce = NULL;

 // Plan comptable
 const AnsiString TTablePC::strfPC_Compte(         szfPC_Compte);
 const AnsiString TTablePC::strfPC_Cycle(          szfPC_Cycle);
 const AnsiString TTablePC::strfPC_TypeEnr(        szfPC_TypeEnr);
 const AnsiString TTablePC::strfPC_CodeDevise(     szfPC_CodeDevise);
 const AnsiString TTablePC::strfPC_Intitule(       szfPC_Intitule);
 const AnsiString TTablePC::strfPC_IntituleLong(   szfPC_IntituleLong);
 const AnsiString TTablePC::strfPC_Lettrable(      szfPC_Lettrable);
 const AnsiString TTablePC::strfPC_Supprime(       szfPC_Supprime);
 const AnsiString TTablePC::strfPC_Visa(           szfPC_Visa);
 const AnsiString TTablePC::strfPC_Flags(          szfPC_Flags);
 const AnsiString TTablePC::strfPC_Drapeaux(       szfPC_Drapeaux);
 const AnsiString TTablePC::strfPC_Debit(          szfPC_Debit);
 const AnsiString TTablePC::strfPC_Credit(         szfPC_Credit);
 const AnsiString TTablePC::strfPC_DebitSituation( szfPC_DebitSituation);
 const AnsiString TTablePC::strfPC_CreditSituation(szfPC_CreditSituation);
 const AnsiString TTablePC::strfPC_DebitTotal(     szfPC_DebitTotal);
 const AnsiString TTablePC::strfPC_CreditTotal(    szfPC_CreditTotal);
 const AnsiString TTablePC::strfPC_SoldeNm1(       szfPC_SoldeNm1);
 const AnsiString TTablePC::strfPC_SoldeNm2(       szfPC_SoldeNm2);
 const AnsiString TTablePC::strfPC_SoldeNm3(       szfPC_SoldeNm3);
 const AnsiString TTablePC::strfPC_SoldeNm4(       szfPC_SoldeNm4);
 const AnsiString TTablePC::strfPC_CompteOrigine(  szfPC_CompteOrigine);
 const AnsiString TTablePC::strfPC_IDImage(        szfPC_IDImage);
 const AnsiString TTablePC::strfPC_CompteAbrege(   szfPC_CompteAbrege);

 AnsiString   TTablePC::cm_strCptPerteArrondis("668800");
 AnsiString   TTablePC::cm_strCptProfiArrondis("768800");
 bool         TTablePC::cm_bIsExEuro           = true;

 TDateTime    cm_DateFinExercice;
 TDateTime    cm_DateSituation;
 bool cm_SoldeVisibleEgalSituation;
// HWND hwndFenetreEICShell = 0;

 // Historique temporaire
 const AnsiString TTableHITmp::strfHITmp_Compte(          szfHITmp_Compte);
 const AnsiString TTableHITmp::strfHITmp_LibelleOperation(szfHITmp_LibelleOperation);
 const AnsiString TTableHITmp::strfHITmp_Piece(           szfHITmp_Piece);
 const AnsiString TTableHITmp::strfHITmp_PieceExterne(    szfHITmp_PieceExterne);
 const AnsiString TTableHITmp::strfHITmp_Debit(           szfHITmp_Debit);
 const AnsiString TTableHITmp::strfHITmp_Credit(          szfHITmp_Credit);
 const AnsiString TTableHITmp::strfHITmp_IDLigne(         szfHITmp_IDLigne);
 const AnsiString TTableHITmp::strfHITmp_Lettrage(        szfHITmp_Lettrage);
 const AnsiString TTableHITmp::strfHITmp_FlagLettrage(    szfHITmp_FlagLettrage);
 const AnsiString TTableHITmp::strfHITmp_RAOData(         szfHITmp_RAOData);
 const AnsiString TTableHITmp::strfHITmp_DateDebPeriode(  szfHITmp_DateDebPeriode);
 const AnsiString TTableHITmp::strfHITmp_DateFinPeriode(  szfHITmp_DateFinPeriode);
 const AnsiString TTableHITmp::strfHITmp_RAOIDLigne(      szfHITmp_RAOIDLigne);
 const AnsiString TTableHITmp::strfHITmp_EstNouvelleLigne(szfHITmp_EstNouvelleLigne);
 const AnsiString TTableHITmp::strfHITmp_Designation(     szfHITmp_Designation);
 const AnsiString TTableHITmp::strfHITmp_CodeTVA(         szfHITmp_CodeTVA);
 const AnsiString TTableHITmp::strfHITmp_TauxTVA(         szfHITmp_TauxTVA);
 const AnsiString TTableHITmp::strfHITmp_DateEcheance(    szfHITmp_DateEcheance);
 const AnsiString TTableHITmp::strfHITmp_ModePaiement(    szfHITmp_ModePaiement);
 const AnsiString TTableHITmp::strfHITmp_Banque(          szfHITmp_Banque);
 const AnsiString TTableHITmp::strfHITmp_Quantite(        szfHITmp_Quantite);
 const AnsiString TTableHITmp::strfHITmp_CodeAnalytik(    szfHITmp_CodeAnalytik);
 const AnsiString TTableHITmp::strfHITmp_DateEP(          szfHITmp_DateEP);
 const AnsiString TTableHITmp::strfHITmp_IDImage(         szfHITmp_IDImage);
 const AnsiString TTableHITmp::strfHITmp_IDImageModifie(  szfHITmp_IDImageModifie);

 // Programme de travail
 const AnsiString TTablePT::strfPT_Racine(       szfPT_Racine);
 const AnsiString TTablePT::strfPT_Ordre(        szfPT_Ordre);
 const AnsiString TTablePT::strfPT_TypeCondition(szfPT_TypeCondition);
 const AnsiString TTablePT::strfPT_Consigne(     szfPT_Consigne);
 const AnsiString TTablePT::strfPT_Visa(         szfPT_Visa);

 int nOldAutoID, nNewAutoID;

 //******************************************************************//
 // Définition des noms des index (utilisés dans le code) des tables //
 //******************************************************************//
 // HI
 const AnsiString TTableHI::striHI_Comptes(    sziHI_Comptes);
 const AnsiString TTableHI::striHI_IDEcritures(sziHI_IDEcritures);


#ifdef _DEBUG
  #define ASSERT_HI_LINE(ptblHI) AssertHILine((ptblHI),__LINE__)
  // Désactivation du message "Non-const function _fastcall Db::TDataSet::FieldByName(const System::AnsiString) called for const object."
  #pragma warn -ncf
  void __fastcall AssertHILine(const TTableHI *ptblHI,unsigned long ulLineNb)
  {
    TIntegerField *pfldInt;
    TFloatField *pfldFloat;
    if (ptblHI && ptblHI->Active)
      {
        pfldInt = (TIntegerField*)ptblHI->FieldByName(TTableHI::strfHI_CodeDevise);
        if(!pfldInt->IsNull)
          {
            pfldFloat = (TFloatField*)ptblHI->FieldByName(TTableHI::strfHI_TauxChange);
            if (EST_DEVISE_EURO(pfldInt->AsInteger))
              {
                if (pfldFloat->IsNull)           //Monnaie zone euro => Taux change null
                  return;
                else
                  ShowMessage("Monnaie zone euro => Taux change null");
              }
            else
              if (pfldFloat->AsFloat > 0.0)      //Devise étrangère (et Euro) => Taux change positif
                return;
              else
                ShowMessage("Devise étrangère (et Euro) => Taux change positif");
          }
        else
          ShowMessage("CodeDevise nul");
      }
    Assert(ulLineNb,__FILE__);
  }
  #pragma warn .ncf
  // Réactivation du message "Non-const function ? called for const object."
#else
  #define ASSERT_HI_LINE(ptblHI)
#endif

void __fastcall ComptaSetAutoID( int nAutoID)
{
  nOldAutoID = nAutoID;
  nNewAutoID = -1;
}

int __fastcall ComptaGetNewAutoID()
{
  return nNewAutoID==-1 ? nOldAutoID : nNewAutoID;
}

void __fastcall ComptaGetListeModePaiement( enum TYPE_LISTE eTypeListe, TStrings *pLstAbreviation, TStrings *pLstDesignation)
{
  if ( pLstAbreviation) { pLstAbreviation->Clear(); pLstAbreviation->Add( EmptyStr); }
  if ( pLstDesignation) { pLstDesignation->Clear(); pLstDesignation->Add( "<Néant>"); }
  for( int i=0; i<MAX_MODE_PAIEMT; i++) {
    if ( LISTE_MODE_PAIEMENT[i].nTypeListe & eTypeListe) {
      if ( pLstAbreviation) pLstAbreviation->Add( LISTE_MODE_PAIEMENT[i].szAbreviation);
      if ( pLstDesignation) pLstDesignation->Add( LISTE_MODE_PAIEMENT[i].szDesignation);
    }
  }
}

enum MODE_PAIEMENT __fastcall ComptaGetModePaiement( const AnsiString &strModePaiemt)
{
  for( int i=0; i<MAX_MODE_PAIEMT; i++)
    if ( AnsiSameText( LISTE_MODE_PAIEMENT[i].szAbreviation,strModePaiemt)) return LISTE_MODE_PAIEMENT[i].eModePaiemt;
  return MP_AUCUN;
}

enum MODE_PAIEMENT __fastcall ComptaGetModePaiementWithDesignation( const AnsiString &strDesignation)
{
  for( int i=0; i<MAX_MODE_PAIEMT; i++)
    if ( AnsiSameText( LISTE_MODE_PAIEMENT[i].szDesignation,strDesignation)) return LISTE_MODE_PAIEMENT[i].eModePaiemt;
  return MP_AUCUN;
}

AnsiString __fastcall ComptaGetDesignationPaiement( const AnsiString &strAbreviation)
{
  for( int i=0; i<MAX_MODE_PAIEMT; i++)
    if ( AnsiSameText(LISTE_MODE_PAIEMENT[i].szAbreviation,strAbreviation)) return LISTE_MODE_PAIEMENT[i].szDesignation;
  return EmptyStr;
}

AnsiString __fastcall ComptaGetModePaiementString( enum MODE_PAIEMENT eModeP)
{
  for( int i=0; i<MAX_MODE_PAIEMT; i++)
    if ( LISTE_MODE_PAIEMENT[i].eModePaiemt==eModeP) return LISTE_MODE_PAIEMENT[i].szDesignation;
  return EmptyStr;
}

AnsiString __fastcall ComptaGetModePaiementAbreviation( enum MODE_PAIEMENT eModeP)
{
  for( int i=0; i<MAX_MODE_PAIEMT; i++)
    if ( LISTE_MODE_PAIEMENT[i].eModePaiemt==eModeP) return LISTE_MODE_PAIEMENT[i].szAbreviation;
  return EmptyStr;
}



__fastcall TTableJnx::TTableJnx(TComponent* pOwner) : inherited(ttDossier, "$$J", pOwner)
{
}


__fastcall TTablePC::TTablePC(TComponent* pOwner) : inherited(ttDossier, "$$A", pOwner)
{
}


__fastcall TTableHI::TTableHI(TComponent* pOwner) : inherited(ttDossier, "$$H", pOwner)
{
  m_bDelLettrage = false;
}

__fastcall TTableHITmp::TTableHITmp(TComponent* pOwner) : inherited("$$H", ttTmp, pOwner)
{
}


__fastcall TTablePT::TTablePT(TComponent* pOwner) : inherited(ttDossier, "$$O", pOwner)
{
}


/******************************************************************************\
************* CJournal::RAZ() **************************************************
********************************************************************************
*                                                                              *
*    Cette méthode remet à zéro tous les attributs du journal.                 *
\******************************************************************************/
void __fastcall CJournal::RAZ()
{
  m_strCode = m_strIntitule = EmptyStr;
  m_eNature = JNNATURE_DEFAULT;
}


/******************************************************************************\
************* CJournal::operator = () ******************************************
********************************************************************************
*                                                                              *
*    Cette fonction permet de copier un journal source.                        *
*                                                                              *
* Paramètres :                                                                 *
*   jnlSrc : Journal source à copier dans l'instance.                          *
*                                                                              *
* Retour :                                                                     *
*   L'instance elle-même.                                                      *
\******************************************************************************/
CJournal& __fastcall CJournal::operator = (const CJournal& jnlSrc)
{
  m_strCode     = jnlSrc.m_strCode;
  m_strIntitule = jnlSrc.m_strIntitule;
  m_eNature     = jnlSrc.m_eNature;
  return *this;
}



/*----------------------------------------------------------------------------*\
------------- TTableJnx::GetAFlagIsOn() ----------------------------------------
--------------------------------------------------------------------------------
-                                                                              -
-    Cette fonction (de lecture des propriétés Est*) permet de savoir si au    -
- moins un des drapeaux passés en paramètre est positionné sur le journal      -
- courant.                                                                     -
-                                                                              -
- Paramètres :                                                                 -
-   fFlags : Drapeaux à tester sur le journal courant.                         -
-                                                                              -
- Retour :                                                                     -
-   TRUE si le journal courant a au moins un des drapeaux passés en paramètre; -
- FALSE sinon.                                                                 -
\*----------------------------------------------------------------------------*/
bool __fastcall TTableJnx::GetAFlagIsOn(int fFlags)
{
  return(FieldByName(strfJN_Flags)->AsInteger & fFlags);
}



bool __fastcall TTableJnx::GetReadOnly()
{
  TStringField *tblCodeJournaux;
  if (VoirJournauxInventaires)
    return GetAFlagIsOn(JNFLAGS_READONLY);
  tblCodeJournaux = (TStringField *)FieldByName(strfJN_Code);
  if ((tblCodeJournaux->AsString == "INVS") || (tblCodeJournaux->AsString == "INVC"))
    return true;
  return GetAFlagIsOn(JNFLAGS_READONLY);
}



 /******************************************************************************\
 ************* TTableJnx::Get() *************************************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de récupérer les propriétés d'un journal existant.  *
 *                                                                              *
 * Paramètres :                                                                 *
 *   strCodeJnl : Code du journal dont on veut les propriétés.                  *
 *   jnl        : Retourne les propriétés du journal demandé.                   *
 \******************************************************************************/
 void __fastcall TTableJnx::Get(const AnsiString& strCodeJnl,
                                 CJournal&         jnl)
 {
  ASSERT(State == dsBrowse);

  if(!Locate(strfJN_Code, strCodeJnl, _loInsensitive))     // Localisation du journal
    EICThrowInvalidArgument(TAG(10));
  // Lecture des propriétés du journal //
  jnl.Code     =                FieldByName(strfJN_Code)->AsString;
  jnl.Nature   = (enum JNNature)FieldByName(strfJN_Nature)->AsInteger;
  jnl.Intitule =                FieldByName(strfJN_Intitule)->AsString;
 }


 /******************************************************************************\
 ************* TTableJnx::Exist() ***********************************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de savoir si un journal, identifié par son code,    *
 * existe dans la table.                                                        *
 *                                                                              *
 * Paramètres :                                                                 *
 *   strCodeJnl : Code du journal dont on veut connaître l'existence.           *
 *                                                                              *
 * Retour :                                                                     *
 *   TRUE si un journal identifié par le code passé en paramètre existe dans la *
 * table; FALSE sinon.                                                          *
 \******************************************************************************/
 bool __fastcall TTableJnx::Exist(const AnsiString& strCodeJnl)
 {
  bool bFound;

  ASSERT(State == dsBrowse);
  ASSERT(!Filtered);

  if (strCodeJnl.IsEmpty() || (strCodeJnl.Length() > FieldByName(strfJN_Code)->Size))
    return false;
  DisableControls();
  try {
    bFound = Locate(strfJN_Code, strCodeJnl, _loInsensitive);   // Recherche du journal
  } catch(Exception& e) {
    EnableControls();
    throw EUser(TAG(20), e);
  }
  EnableControls();
  return bFound;
 }


 /******************************************************************************\
 ************* TTableJnx::Nature() **********************************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette fonction donne la nature d'un journal d'après son code.             *
 *                                                                              *
 * Paramètres :                                                                 *
 *   strCodeJnl  : Code (existant) du journal dont on veut obtenir la nature.   *
 *                                                                              *
 * Note : Si le journal n'existe pas, une exception EUser est levée.            *
 \******************************************************************************/
 enum JNNature __fastcall TTableJnx::Nature(const AnsiString& strCodeJnl)
 {
  if(!Locate(strfJN_Code, strCodeJnl, _loInsensitive))
    throw EUser(TAG(30),"Code journal non trouvé.\n"
                              "\n"
                              "Faire une réparation comptable (Liste des dossiers, menu 'Outils').\n"
                              "Si le problème persiste contacter l'assistance téléphonique.");
  return((enum JNNature)FieldByName(strfJN_Nature)->AsInteger);
 }


 /******************************************************************************\
 ************* TTableJnx::Creer() ***********************************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de créer un nouveau journal.                        *
 *                                                                              *
 * Paramètres :                                                                 *
 *   jnl : Journal à créer.                                                     *
 *                                                                              *
 * Retour :                                                                     *
 *   TRUE si le journal a bien pu être créé; FALSE sinon (dans ce cas, c'est que*
 * le code du journal à créer existe déjà).                                     *
 \******************************************************************************/
 bool __fastcall TTableJnx::Creer(const CJournal& jnl)
 {
  DWORD dwModalSais;
  ASSERT(Active && (State == dsBrowse));
  ASSERT(!Filtered);


  //////////////////////////////////////////////
  // Vérification de l'utilité de l'opération //
  //////////////////////////////////////////////
  if(Exist(jnl.Code) ||
      ((jnl.Nature == JNNATURE_A_NOUVEAUX) &&
        Locate(strfJN_Nature, JNNATURE_A_NOUVEAUX, _loNormal)))
    return(false);   // Le journal existe déjà ou bien un journal d'"A Nouveaux" existe déjà => On ne le créé pas
  // Création du nouveau journal //
  try {
    Insert();

    ASSERT(FieldByName(strfJN_Flags)->AsInteger == JNFLAGS_AUCUN);

    FieldByName(strfJN_Code)->AsString     = jnl.Code;
    FieldByName(strfJN_Intitule)->AsString = jnl.Intitule.IsEmpty() ? AnsiString(_strPtInterro) : jnl.Intitule;
    FieldByName(strfJN_Nature)->AsInteger  = (int)jnl.Nature;
    if ((jnl.Nature == JNNATURE_ACHATS && CocheOCRpourJournauxAchat) || (jnl.Nature == JNNATURE_VENTES && CocheOCRpourJournauxVente))
    {
      dwModalSais = TTableJnx::JNAchVntModalSaisGen_DEFAULT;
      dwModalSais |= JNAchVntModalSaisGen_MONTANT_HT;
      FieldByName(strfJN_AchVntModalSais)->AsInteger  = dwModalSais;
      FieldByName(strfJN_AchVntDematModalSais)->AsInteger  = dwModalSais;
    }
    Post();
    FlushBuffers();
  } catch(Exception& e) {
    Cancel();
    throw;
  }
  return(true);
 }


 /******************************************************************************\
 ************* TTableJnx::CreerDlg() ********************************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de créer un nouveau journal par l'intermédiaire     *
 * d'une boîte de dialogue appropriée.                                          *
 *                                                                              *
 * Paramètres :                                                                 *
 *   tag           : Tag dans l'appelant                                        *
 *   strNewCodeJnl : Code du nouveau journal à créer (vide=saisie du code)      *
 *   bExisteDeja   : Retourne TRUE si le journal existe déjà et n'a pas besoin  *
 *                   d'être créé.                                               *
 *   hInstance     : Instance de l'appelant                                     *
 *                                                                              *
 * Retour :                                                                     *
 *   TRUE si le journal a bien pu être créé; FALSE sinon (dans ce cas, c'est que*
 * le code du journal à créer existe déjà ou que l'utilisateur a abandonné la   *
 * création).                                                                   *
 \******************************************************************************/
 bool __fastcall TTableJnx::CreerDlg(EICTag            tag,
                                      const AnsiString& strNewCodeJnl,
                                      bool&             bExisteDeja,
                                      void*             hInstance) // = HInstance
 {
  TdlgModCreJnl* pdlgCreerJnl = NULL; // Dialogue de création d'un journal
  bool           bCreated = false;     // TRUE si un journal a été effectivement créé

  ASSERT(Active && (State == dsBrowse));
  ASSERT(!Filtered);

  if(Exist(strNewCodeJnl))
  { // Le journal existe déjà
    // => On ne le créé pas
    bExisteDeja = true;
    return(false);
  }
  bExisteDeja = false;
  // Affichage du dialogue de création d'un journal
  try {
    pdlgCreerJnl = new TdlgModCreJnl(false, this, strNewCodeJnl);
    if(pdlgCreerJnl->ShowModal() == mrOk)
    { // Un nouveau journal a été créé
      bCreated = true;
    }
    delete pdlgCreerJnl;
  } catch(Exception& e) {
    EICDisplayException(tag, e, hInstance);
    delete pdlgCreerJnl;
  }
  return(bCreated);
 }



AnsiString __fastcall TTableJnx::Selectionner(bool VoirEIC,bool VoirReadOnly)
{
  TdlgSelectJnl *dlgSelectJnl = NULL;
  AnsiString CodeJournal;
  try
    {
      dlgSelectJnl = new TdlgSelectJnl(this,&CodeJournal,VoirEIC,VoirReadOnly);
      dlgSelectJnl->ShowModal();
    }
  catch (Exception &e)
    {
      EICDisplayException(TAGL,e);
    }
  delete dlgSelectJnl;
  return CodeJournal;
}



 /******************************************************************************\
 ************* TTableJnx::Modifier() ********************************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette procédure permet de modifier les caractéristiques (sauf les flags)  *
 * d'un journal.                                                                *
 *                                                                              *
 * Paramètres :                                                                 *
 *   jnl : Journal à mettre à jour dans la table.                               *
 \******************************************************************************/
 void __fastcall TTableJnx::Modifier(const CJournal& jnl)
 {
  TIntegerField* pfldNature;

  ASSERT(!IsEmpty());
  ASSERT(State == dsBrowse);


  try {
    if(!Locate(strfJN_Code, jnl.Code, _loInsensitive))    // Localisation du journal
      EICThrowInvalidArgument(TAG(40));   // Code journal non trouvé
    // Vérification de la possibilité de modification
    pfldNature = (TIntegerField*)FieldByName(strfJN_Nature);
    if((jnl.Nature == JNNATURE_A_NOUVEAUX) &&
        (pfldNature->AsInteger != JNNATURE_A_NOUVEAUX) &&
        Locate(strfJN_Nature, JNNATURE_A_NOUVEAUX, _loNormal))
    { // Erreur: On veut modifier un journal en lui mettant une nature "A Nouveaux"
      //         alors qu'il existe déjà un journal d'"A Nouveaux"
      // => Erreur (il ne peut y avoir qu'un seul journal d'"A Nouveau" dans une table
      EICThrowInvalidArgument(TAG(41), IDS_EXCEPTION_JOURNAL_A_NOUVEAU_DEJA_EXISTANT);
    }

    Edit();

    pfldNature->AsInteger                   = (int)jnl.Nature;
    FieldByName(strfJN_Intitule)->AsString = jnl.Intitule;

    Post();

    FlushBuffers();
  } catch(Exception& e) {
    Cancel();
    throw EUser(TAG(42), e);
  }
 } /* TTableJnx::Modifier() */


 /******************************************************************************\
 ************* TTableJnx::ModifierCourantDlg() **********************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de modifier le journal courant par l'intermédiaire  *
 * d'une boîte de dialogue appropriée.                                          *
 *                                                                              *
 * Paramètres :                                                                 *
 *   tag : Tag de l'opération                                                   *
 *                                                                              *
 * Retour :                                                                     *
 *   TRUE si le journal courant a été modifié; FALSE sinon (i.e. l'utilisateur  *
 * a abandonné le dialogue de modification).                                    *
 \******************************************************************************/
 bool __fastcall TTableJnx::ModifierCourantDlg(EICTag tag)
 {
  TdlgModCreJnl* pdlgModifierJnl; // Dialogue de modification du journal courant
  bool           bModified;       // TRUE si le journal courant est modifié

  ASSERT(Active && (State == dsBrowse) && !Filtered);
  ASSERT(!IsEmpty());


  ////////////////////////////////////////////////////////
  // Affichage du dialogue de modification d'un journal //
  ////////////////////////////////////////////////////////
  bModified       = false;
  pdlgModifierJnl = NULL;
  try {
    pdlgModifierJnl = new TdlgModCreJnl(true, this, FieldByName(strfJN_Code)->AsString);
    if(pdlgModifierJnl->ShowModal() == mrOk)
    { // Le journal courant a été modifié
      bModified = true;
    }
    pdlgModifierJnl->Release();
  } catch(Exception& e) {
    EICDisplayException(tag, e);
    delete pdlgModifierJnl;
  }
  return(bModified);
 } /* TTableJnx::ModifierCourantDlg() */

void __fastcall TTableJnx::GetNaturesJnl( TStrings *pNatures)
{
  pNatures->Clear();
  pNatures->Add( "Opérations diverses");
  pNatures->Add( "A nouveaux"         );
  pNatures->Add( "Achats"             );
  pNatures->Add( "Ventes"             );
  pNatures->Add( "Trésorerie"         );
  pNatures->Add( "Inventaire"         );
  pNatures->Add( "Balance"            );
}

AnsiString __fastcall TTableJnx::GetTextNature( JNNature eNature)
{
  TStrings  *pNatures;
  AnsiString strText;
  try {
    pNatures = new TStringList();
    GetNaturesJnl( pNatures);
    if ( eNature>=pNatures->Count) strText = "!!! NATURE INCONNUE !!!";
                              else strText = pNatures->Strings[eNature];
    delete pNatures;
  } catch( Exception &e) {
    throw EUser( TAG( 1410), e);
  }
  return strText;
}


 //*********//
 // CCompte //
 //*********/////////////////////////////////////////////////////////////////////
 //                                                                            //
 //    Cette classe permet de stocker les attributs d'un compte du PC.         //
 ////////////////////////////////////////////////////////////////////////////////
 __fastcall CCompte::CCompte()
 {
  RAZ();
 }

 __fastcall CCompte::CCompte(const char* pcszCompte,
                              const char* pcszIntitule)
 {
  RAZ();
  m_strCompte   = pcszCompte;
  m_strIntitule = pcszIntitule;
 }


 /******************************************************************************\
 ************* CCompte::RAZ() ***************************************************
 ********************************************************************************
 *                                                                              *
 *    Cette méthode remet à zéro tous les attributs du compte.                  *
 \******************************************************************************/
 void __fastcall CCompte::RAZ()
 {
  m_strCompte       = EmptyStr;
  m_strIntitule     = EmptyStr;
  m_strIntituleLong = EmptyStr;
  m_eCodeDevise     = CODE_DEVISE_DEFAUT;
  m_curDebit        = 0.0;
  m_curCredit       = 0.0;
  m_bMouvementeNm1  = false;
  m_curSoldeNm1     = 0.0;
  m_bMouvementeNm2  = false;
  m_curSoldeNm2     = 0.0;
  m_bMouvementeNm3  = false;
  m_curSoldeNm3     = 0.0;
  m_bMouvementeNm4  = false;
  m_curSoldeNm4     = 0.0;
  m_bRANDetaille    = false;
  m_bSaisiePeriodes = false;
  m_bSupprime       = false;
  m_CompteO = EmptyStr;
  m_strCompteAbrege = EmptyStr;
 }


 /******************************************************************************\
 ************* CCompte::operator = () *******************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de copier un compte source.                         *
 *                                                                              *
 * Paramètres :                                                                 *
 *   cptSrc : Compte source à copier dans l'instance.                           *
 *                                                                              *
 * Retour :                                                                     *
 *   L'instance elle-même.                                                      *
 \******************************************************************************/
 CCompte& __fastcall CCompte::operator = (const CCompte& cptSrc)
 {
  if(&cptSrc != this)
  {
    m_strCompte       = cptSrc.m_strCompte;
    m_strIntitule     = cptSrc.m_strIntitule;
    m_strIntituleLong = cptSrc.m_strIntituleLong;
    m_eCodeDevise     = cptSrc.m_eCodeDevise;
    m_curDebit        = cptSrc.m_curDebit;
    m_curCredit       = cptSrc.m_curCredit;
    m_bMouvementeNm1  = cptSrc.m_bMouvementeNm1;
    m_curSoldeNm1     = cptSrc.m_curSoldeNm1;
    m_bMouvementeNm2  = cptSrc.m_bMouvementeNm2;
    m_curSoldeNm2     = cptSrc.m_curSoldeNm2;
    m_bMouvementeNm3  = cptSrc.m_bMouvementeNm3;
    m_curSoldeNm3     = cptSrc.m_curSoldeNm3;
    m_bMouvementeNm4  = cptSrc.m_bMouvementeNm4;
    m_curSoldeNm4     = cptSrc.m_curSoldeNm4;
    m_bRANDetaille    = cptSrc.m_bRANDetaille;
    m_bSaisiePeriodes = cptSrc.m_bSaisiePeriodes;
    m_bSupprime       = cptSrc.m_bSupprime;
    m_strCompteAbrege = cptSrc.m_strCompteAbrege;
  }

  return(*this);
 }


 //**********//
 // TTablePC //
 //**********////////////////////////////////////////////////////////////////////
 //                                                                            //
 //    Cette classe permet de gérer une table "Plan Comptable".                //
 ////////////////////////////////////////////////////////////////////////////////
 /*============================================================================*\
 ============= TTablePC::InitClassMembers() =====================================
 ================================================================================
 =                                                                              =
 =    Cette fonction permet d'initialiser les membres de classe des tables PC   =
 = (elle est implémentée pour une initialisation rapide à partir des modules 16 =
 = bits).                                                                       =
 =                                                                              =
 = Paramètres :                                                                 =
 =   strCptPerteArrondis  : Nouveau compte de pertes  sur arrondis avec l'Euro  =
 =   strCptProfiArrondis  :    "      "    "  profits  "     "      "      "    =
 =   bIsExNEuro           : TRUE si monnaie de tenue exercice  N   est  l'Euro  =
 =   bIsExNm1Euro         :  "   "     "    "    "       "    N-1 était   "     =
 =   bIsExNm2Euro         :  "   "     "    "    "       "    N-2   "     "     =
 =                                                                              =
 = Remarque : Si un paramètre est incorrect, une exception est levée.           =
 \*============================================================================*/
 void __fastcall TTablePC::InitClassMembers( bool             bIsExEuro,
                                             const TDateTime &DateFinExercice,
                                             const TDateTime &DateSituation,
                                             bool Situation)
 {
  #pragma message("*** TTablePC::InitClassMembers(): Changement des comptes de perte sur arrondis à faire... ***" )
  cm_bIsExEuro = bIsExEuro;
  switch( _CodePays) {
    case CP_FRANCE  : DeviseChangeDefaut( cm_bIsExEuro ? DeviseCodeEuro : DeviseCodeFranc);
                      break;
    case CP_TUNISIE : ASSERT( cm_bIsExEuro);
                      DeviseChangeDefaut( DeviseCodeEuro);
                      break;
    default         : ASSERT( false);
                      break;
  }

  cm_DateFinExercice = DateFinExercice;
  cm_DateSituation = DateSituation;
  cm_SoldeVisibleEgalSituation = Situation;
 }


 /*============================================================================*\
 ============= TTablePC::GetEstUnCompteCollectif() ==============================
 ================================================================================
 =                                                                              =
 =    Cette fonction permet de savoir si un compte est un compte                =
 = collectif ou non.                                                           =
 =                                                                              =
 = Paramètres :                                                                 =
 =                                                                              =
 = Retour :                                                                     =
 =   TRUE si le compte est collectif; FALSE sinon                              =
 =                                                                              =
 \*============================================================================*/
bool __fastcall TTablePC::GetEstUnCompteCollectif()
{
  ASSERT(Active);

  return FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_COMPTE_COLLECTIF;
}




bool __fastcall TTablePC::GetEstUnCompte()
{
  ASSERT(Active);

  return FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_COMPTE;
}




bool __fastcall TTablePC::GetEstUnCompteNormal()
{
  ASSERT(Active);

  return EstUnCompte && !EstAuxiliaire;
}




bool __fastcall TTablePC::GetEstUnCompteAuxiliaire()
{
  ASSERT(Active);

  return EstUnCompte && EstAuxiliaire;
}




bool __fastcall TTablePC::GetEstUnProgrammeDeTravail()
{
  ASSERT(Active);

  return FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_PROGRAMME_DE_TRAVAIL;
}



 //----------------------------------------------------------------------------
 //
 // Verifie l'existence d'un compte
 //
 bool __fastcall TTablePC::EstUnCompteExistant(const AnsiString& strCompte)
 {
  bool      bRet;
  TBookmark oldBookMark;

  ASSERT(State == dsBrowse);

  bRet = false;
  if(!strCompte.IsEmpty())
  {
    Refresh();
    DisableControls();

    oldBookMark = GetBookmark();

    if(AllerSurLeCompte(strCompte))
      bRet = true;

    GotoBookmark(oldBookMark);
    FreeBookmark(oldBookMark);

    EnableControls();
  }

  return(bRet);
 }


 /*----------------------------------------------------------------------------*\
 ------------- TTablePC::GetSolde() ---------------------------------------------
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette fonction (de lecture des propriétés SoldeXXX) donne le solde de     -
 - l'exercice N, N-1 ou N-2.                                                    -
 -    Le solde est la valeur "Débit" - "Crédit"                                 -
 -                                                                              -
 - Paramètres :                                                                 -
 -   eIDExercice : Une valeur IDEXERCICE_*                                      -
 \*----------------------------------------------------------------------------*/
 Currency __fastcall TTablePC::GetSolde(int eIDExercice)
 {
  Currency curSolde; // Valeur de retour de la fonction


  /////////////////////
  // Calcul du solde //
  /////////////////////
  TField* pfld = FieldByName((eIDExercice == IDEXERCICE_Nm2) ? strfPC_SoldeNm2 :
                             (eIDExercice == IDEXERCICE_Nm1) ? strfPC_SoldeNm1 :
                                                               strfPC_Debit);

  if(!pfld->IsNull)
    curSolde = pfld->AsCurrency;
  else
  {
    ASSERT(curSolde == (double)0.0);
  }

  if(eIDExercice == IDEXERCICE_N)
    {
      if(!((pfld = FieldByName(strfPC_Credit))->IsNull))
        curSolde -= pfld->AsCurrency;
    }
  return(curSolde);
 }


 /*----------------------------------------------------------------------------*\
 ------------- TTablePC::GetEstMouvemente() -------------------------------------
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette fonction (de lecture des propriétés EstMouvementeXXX) indique si le -
 - compte courant est mouvementé sur l'exercice N ou N-x.                       -
 -                                                                              -
 - Retour :                                                                     -
 -   TRUE si le compte est mouvementé sur l'exercice en question; FALSE sinon.  -
 \*----------------------------------------------------------------------------*/
 bool __fastcall TTablePC::GetEstMouvemente(int eIDExercice)
 {
  switch(eIDExercice)
  { case IDEXERCICE_Nm4 : return(!FieldByName(strfPC_SoldeNm4)->IsNull);
    case IDEXERCICE_Nm3 : return(!FieldByName(strfPC_SoldeNm3)->IsNull);
    case IDEXERCICE_Nm2 : return(!FieldByName(strfPC_SoldeNm2)->IsNull);
    case IDEXERCICE_Nm1 : return(!FieldByName(strfPC_SoldeNm1)->IsNull);
    case IDEXERCICE_N: return(!FieldByName(strfPC_Debit)->IsNull ||
                              !FieldByName(strfPC_Credit)->IsNull);
    case IDEXERCICE_Np1: return(!FieldByName(strfPC_DebitTotal)->IsNull ||
                                !FieldByName(strfPC_CreditTotal)->IsNull);
    default:
      if (FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_COMPTE)
        return (!FieldByName(strfPC_DebitTotal)->IsNull ||
                !FieldByName(strfPC_CreditTotal)->IsNull ||
                !FieldByName(strfPC_SoldeNm2)->IsNull ||
                !FieldByName(strfPC_SoldeNm1)->IsNull ||
                !FieldByName(strfPC_SoldeNm3)->IsNull ||
                !FieldByName(strfPC_SoldeNm4)->IsNull);
      else
        return true;
  }
 }


 /*----------------------------------------------------------------------------*\
 ------------- TTablePC::GetEstVise() -------------------------------------------
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette fonction (de lecture des propriétés EstVise*) permet de savoir si   -
 - le compte/PT courant est visé (au niveau final ou ordinaire).                -
 -                                                                              -
 - Paramètres :                                                                 -
 -   bViseFinal : TRUE/FALSE pour savoir si le compte est visé final/ordinaire  -
 -                (paramètre ignoré lorsque l'enregistrement courant est un PT).-
 -                                                                              -
 - Retour :                                                                     -
 -   TRUE si le compte courant est visé selon bViseFinal; FALSE sinon.          -
 \*----------------------------------------------------------------------------*/
 bool __fastcall TTablePC::GetEstVise(int bViseFinal)
 {
  int fVisas; // Visas du compte/PT actuel

  ASSERT((State == dsBrowse) || (State == dsFilter) || (State == dsEdit));
  ASSERT((FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_COMPTE) ||
          (FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_PROGRAMME_DE_TRAVAIL) ||
          (FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_COMPTE_COLLECTIF));


  ///////////////////////////////////////////
  // Lecture des visas du compte/PT actuel //
  ///////////////////////////////////////////
  fVisas = FieldByName(strfPC_Visa)->AsInteger;

  if(FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_PROGRAMME_DE_TRAVAIL)
  { // On souhaite savoir si le PT est visé
    //ASSERT((fVisas == PCVISA_AUCUN) || (fVisas == PCVISA_PROGRAMME_DE_TRAVAIL));
    return(fVisas != PCVISA_AUCUN);
  }
  else if(bViseFinal)
  { // On souhaite savoir si le compte est visé au niveau final
    // => Cela est vrai si le visa final est positionné ou
    //                  si le visa ordinaire peut être "assimilé" visa final (i.e. si
    //                  le compte est visé ordinaire et qu'il ne fait pas partie du cycle final)
    if(fVisas & PCVISA_FINAL_PAR_FINAL)
    { // Ce compte est visé final (il fait donc partie du cycle final)
      ASSERT(FieldByName(strfPC_Flags)->AsInteger & PCFLAGS_COMPTE_CYCLE_FINAL);
      return(true);
    }
    else if(FieldByName(strfPC_Flags)->AsInteger & PCFLAGS_COMPTE_CYCLE_FINAL)
    { // Ce compte est non visé final et appartient au cycle final
      // => Il n'est pas visé final
      return(false);
    }
    else
    { // Ce compte est non visé final et N'APPARTIENT PAS au cycle final
      // => Son(ses) visa(s) ordianire(s) peu(ven)t être assimilé(s) visa final
      //    On sort du if(bViseFinal) pour savoir s'il est visé ordinaire
    }
  }

  // On souhaite savoir si le compte est visé ordinaire
  // => Cela est vrai s'il a été visé ordinaire par son cycle ordinaire ou par le cycle final
  return(fVisas & (PCVISA_ORDINAIRE_PAR_ORDINAIRE | PCVISA_ORDINAIRE_PAR_FINAL));
 } /* TTablePC::GetEstVise() */



 /*----------------------------------------------------------------------------*\
 ------------- TTablePC::GetResultat() ------------------------------------------
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette fonction (de lecture de la propriété Resultat) retourne le résultat -
 - comptable de l'exercice i.e. le cumul des comptes 7 (Crédit-Débit) moins le  -
 - cumul des comptes 6 (Débit-Crédit).                                          -
 -                                                                              -
 - Retour :                                                                     -
 -   Le résultat de l'exercice.                                                 -
 -                                                                              -
 - Note : Le réultat revient au cumul inversé des soldes (Débit-Crédit) des     -
 -        comptes 6 et 7.                                                       -
 \*----------------------------------------------------------------------------*/
Currency __fastcall TTablePC::GetResultat()
{
  bool AncienFiltered;
  TFilterRecordEvent AncienFilterRecord;
  Currency ResultatCourant;
  AnsiString AncienFilter,AncienBookmark;

  ASSERT(!MasterSource);

  AncienFilter = Filter;
  AncienFiltered = Filtered;
  AncienFilterRecord = OnFilterRecord;
  AncienBookmark = Bookmark;
  DisableControls();
  Filter = szfPC_Compte ">='6' AND " szfPC_Compte "<'8'";
  Filtered = true;
  First();
  ResultatCourant = 0.0;
  while (!Eof)
    {
      if (EstUnCompte)
        ResultatCourant -= Solde;
      Next();
    }
  Filtered = AncienFiltered;
  OnFilterRecord = AncienFilterRecord;
  Filter = AncienFilter;
  Bookmark = AncienBookmark;
  EnableControls();
  return ResultatCourant;
 }




Currency __fastcall TTablePC::GetResultatSituation()
{
  bool AncienFiltered;
  char Classe;
  TCurrencyField *tblPCDebit,*tblPCCredit;
  TStringField *tblPCCompte;
  Currency ResultatSit;
  AnsiString AncienBookmark;
  CSablier Sablier;

  ASSERT(!MasterSource);

  try
    {
      DisableControls();
      AncienBookmark = Bookmark;
      AncienFiltered = Filtered;
      Filtered = false;
      ResultatSit = 0.0;
      First();
      tblPCCompte = (TStringField *)FieldByName(TTablePC::strfPC_Compte);
      tblPCDebit = (TCurrencyField *)FieldByName(TTablePC::strfPC_Debit);
      tblPCCredit = (TCurrencyField *)FieldByName(TTablePC::strfPC_Credit);
      while (!Eof)
        {
          Classe = AnsiString(tblPCCompte->AsString)[1];
          if (EstUnCompte && (Classe >= '6') && (Classe <= '7'))
            ResultatSit += tblPCCredit->AsCurrency - tblPCDebit->AsCurrency;
          Next();
        }
      if (AncienFiltered)
        Filtered = AncienFiltered;
      Bookmark = AncienBookmark;
      EnableControls();
    }
  catch(Exception &e)
    {
      Bookmark = AncienBookmark;
      EnableControls();
      throw EUser(TAGL,e);  //TAG(1)
    }
  return ResultatSit;
}




bool __fastcall TTablePC::ChangerSoldes(bool Situation)
{
  TCurrencyField *tblPCDebit,*tblPCCredit,*tblPCDebitSituation,*tblPCCreditSituation,*tblPCDebitTotal,*tblPCCreditTotal;
  CBarre Barre;

  ASSERT(!Filtered);
  ASSERT(!MasterSource);

  try
    {
      Barre.Messages = Situation ? "Chargement des soldes de situation" : "Chargement des soldes courants";
      Barre.Titre = "Données de situation";
      Barre.Open();
      Barre.Max = RecordCount;
      Barre = 0;
      First();
      tblPCDebit = (TCurrencyField *)FieldByName(TTablePC::strfPC_Debit);
      tblPCCredit = (TCurrencyField *)FieldByName(TTablePC::strfPC_Credit);
      tblPCDebitTotal = (TCurrencyField *)FieldByName(TTablePC::strfPC_DebitTotal);
      tblPCCreditTotal = (TCurrencyField *)FieldByName(TTablePC::strfPC_CreditTotal);
      tblPCDebitSituation = (TCurrencyField *)FieldByName(TTablePC::strfPC_DebitSituation);
      tblPCCreditSituation = (TCurrencyField *)FieldByName(TTablePC::strfPC_CreditSituation);
      while (!Eof)
        {
          Edit();
          if (Situation)
            {
              if (tblPCDebitSituation->IsNull)
                tblPCDebit->Clear();
              else
                tblPCDebit->AsCurrency = tblPCDebitSituation->AsCurrency;
              if (tblPCCreditSituation->IsNull)
                tblPCCredit->Clear();
              else
                tblPCCredit->AsCurrency = tblPCCreditSituation->AsCurrency;
            }
          else
            {
              if (tblPCDebitTotal->IsNull)
                tblPCDebit->Clear();
              else
                tblPCDebit->AsCurrency = tblPCDebitTotal->AsCurrency;
              if (tblPCCreditTotal->IsNull)
                tblPCCredit->Clear();
              else
                tblPCCredit->AsCurrency = tblPCCreditTotal->AsCurrency;
            }
          Next();
          Barre++;
        }
      Barre.Close();
    }
  catch(Exception &e)
    {
      EICDisplayException(TAGL,e);
      EICErreur("Une erreur est survenue dans la mise à jour des soldes.");
      Barre.Close();
      return false;
    }
  return true;
}




/******************************************************************************\
************* TTablePC::AllerSurLeCompte() *************************************
********************************************************************************
*                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
********************************************************************************
*                                                                              *
*    Cette fonction permet de retourner un compte du PC.                       *
*                                                                              *
* Paramètres :                                                                 *
*   strCompte : Compte à rechercher dans le PC                                 *
*                                                                              *
* Retour :                                                                     *
*   TRUE si le compte a été trouvé dans le PC (auquel cas, l'enregistrement    *
* courant est le compte lui-même); FALSE sinon (dans ce cas, l'enregistrement  *
* courant est un enregistrement quelconque).                                   *
\******************************************************************************/
bool __fastcall TTablePC::AllerSurLeCompte(const AnsiString& strCompte)
{
  ASSERT(State == dsBrowse);


  if (Locate(strfPC_Compte,strCompte,_loNormal))
    do
      {
        if(FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_COMPTE)
          return true;                           //Le compte est bien dans le PC
        Next();
      }
    while (!Eof && (FieldByName(strfPC_Compte)->AsString == strCompte));
  else if (strCompte.Length() > 1 && strCompte.Length() <= 6 &&  (strCompte[1] == ';' || strCompte[1] == '.'))
  {
    //On demande à rechercher à partir du compte abrégé
    return AllerSurLeCompteAbrege(strCompte.SubString(2,strCompte.Length()-1));
  }
  return false;
}

/******************************************************************************\
************* TTablePC::AllerSurLeCompteAbrege() *******************************
********************************************************************************
*                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
********************************************************************************
*                                                                              *
*    Cette fonction permet de retourner un compte du PC.                       *
*                                                                              *
* Paramètres :                                                                 *
*   pCompteAbrege : Compte abrégé à rechercher dans le PC                      *
*                                                                              *
* Retour :                                                                     *
*   TRUE si le compte a été trouvé dans le PC (auquel cas, l'enregistrement    *
* courant est le compte lui-même); FALSE sinon (dans ce cas, l'enregistrement  *
* courant est un enregistrement quelconque).                                   *
\******************************************************************************/
bool __fastcall TTablePC::AllerSurLeCompteAbrege(const AnsiString& pCompteAbrege)
{
  ASSERT(State == dsBrowse);
  if (Locate(strfPC_CompteAbrege,pCompteAbrege,_loInsensitive))
    do
      {
        if(FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_COMPTE)
          return true;                           //Le compte est bien dans le PC
        Next();
      }
    while (!Eof && (FieldByName(strfPC_Compte)->AsString == pCompteAbrege));
  return false;
}


bool __fastcall TTablePC::AllerSurLeCompteCollectif(const AnsiString &Collectif)
{
  if (Locate(strfPC_Compte,Collectif,_loNormal))
    do
      {
        if (FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_COMPTE_COLLECTIF)
          return true;
        Next();
      }
    while (!Eof && (FieldByName(strfPC_Compte)->AsString == Collectif));
  return false;
}




/******************************************************************************\
************* TTablePC::GetCompte() ********************************************
********************************************************************************
*                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
********************************************************************************
*                                                                              *
*    Cette fonction permet de retourner un compte du PC.                       *
*                                                                              *
* Paramètres :                                                                 *
*   strCompte : Compte à rechercher dans le PC                                 *
*   cpt       : Retourne le compte (avec ses caractéristiques)                 *
*                                                                              *
* Retour :                                                                     *
*   TRUE si le compte a été trouvé dans le PC et que le paramètre "cpt" a pu   *
* être correctement rempli; FALSE sinon.                                       *
*                                                                              *
* Note : Si une erreur quelconque survient, la fonction retourne FALSE.        *
\******************************************************************************/
bool __fastcall TTablePC::GetCompte(const AnsiString& strCompte,CCompte &cpt)
{
  if (AllerSurLeCompte(strCompte))
    { // Le compte existe bien
      // => Lecture de ses propriétés
      GetCompteCourant(cpt);

      ASSERT(cpt.Compte == strCompte || cpt.CompteAbrege.UpperCase() == strCompte.SubString(2,strCompte.Length()-1).UpperCase());

      return true;
    }
  else
    { // Compte non trouvé
      cpt.RAZ();
      return false;
    }
}

 //----------------------------------------------------------------------------
 //
 // Verifie l'existence d'un compte abrégé
 //
 bool __fastcall TTablePC::EstUnCompteAbregeExistant(const AnsiString& pCompteAbrege,const AnsiString& pCompte)
 {
  bool      bRet;
  TBookmark oldBookMark;

  ASSERT(State == dsBrowse);

  bRet = false;
  if(!pCompteAbrege.IsEmpty())
  {
    Refresh();
    DisableControls();

    oldBookMark = GetBookmark();

    if(AllerSurLeCompteAbrege(pCompteAbrege)&& FieldByName(strfPC_Compte)->AsString != pCompte)
    {
      EICAttention("Ce compte abrégé existe déjà pour le compte '" + FieldByName(strfPC_Compte)->AsString + "'.\n\nVeuillez corriger votre saisie S.V.P.");
      bRet = true;
    }
    GotoBookmark(oldBookMark);
    FreeBookmark(oldBookMark);

    EnableControls();
  }

  return(bRet);
 }



bool __fastcall CCompte::EstUnCompteValide(const char* pcszCompte)
{
  char c;
  if (!pcszCompte)
    return false;
  switch (*pcszCompte)
    {
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        break;
      default:
        return false;
    }
  for (int i = strlen(pcszCompte) - 1;i > 0;i--)          //i > 0 pour ne pas tester le premier caractère qui est déjà testé avant
    {
      c = *(pcszCompte + i);
      if (!(((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9'))))
        return false;                                     //Il n'y a pas que des chiffres et des lettres
    }
  return true;
}



/******************************************************************************\
************* TTablePC::CreerCompte() ******************************************
********************************************************************************
*                                                                              *
*    Cette fonction permet de créer un nouveau compte (sans débits/crédits     *
* initiaux).                                                                   *
*                                                                              *
* Paramètres :                                                                 *
*   cpt : Compte à créer (les débits et soldes sont ignorés).                  *
*                                                                              *
* Retour :                                                                     *
*   TRUE si le compte n'existe pas déjà et a bien été créé; FALSE sinon.       *
*                                                                              *
* Note : Si une erreur quelconque survient, une exception est levée.           *
\******************************************************************************/
bool __fastcall TTablePC::CreerCompte(const CCompte &cpt)
{
  bool bIntoCycleFinal, // TRUE si le compte à créer fait partie du cycle final
       bTmp,NouveauCompteAuxiliaire;
  TTablePC *tblPC;
  CPosteDLL PosteDll;
  ASSERT(State == dsBrowse);
  ASSERT(!MasterSource);

  if (!CCompte::EstUnCompteValide(cpt.Compte.c_str()))
    return false;
  if (EstUnCompteExistant(cpt.Compte))
    return false;        // Le compte existe déjà
  if(cpt.Compte.IsEmpty())
    EICThrowInvalidArgument(TAG(50));
  try {
    tblPC = 0;
    tblPC = new TTablePC(0);
    tblPC->Open();
    NouveauCompteAuxiliaire = tblPC->AllerSurLeCompteCollectifDe(cpt.Compte);         //Le nouveau compte est-il auxiliaire ?
    tblPC->Close();
    delete tblPC;
    tblPC = 0;
    if (cpt.Intitule.IsEmpty() && DlgCreerCompte(this,cpt))
      return true;
    Insert();

    ASSERT(FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_COMPTE);
    ASSERT(FieldByName(strfPC_Visa)->AsInteger    == PCVISA_AUCUN);
    ASSERT(FieldByName(strfPC_Debit)->IsNull);
    ASSERT(FieldByName(strfPC_Credit)->IsNull);
    ASSERT(FieldByName(strfPC_SoldeNm1)->IsNull);
    ASSERT(FieldByName(strfPC_SoldeNm2)->IsNull);
    ASSERT(FieldByName(strfPC_Drapeaux)->AsInteger == PCDRAPEAUX_AUCUN);

    FieldByName(strfPC_Compte)->AsString       = cpt.Compte;
    FieldByName(strfPC_CompteOrigine)->AsString = cpt.CompteOrigine;
    FieldByName(strfPC_CompteAbrege)->AsString = cpt.CompteAbrege;
    FieldByName(strfPC_Intitule)->AsString     = cpt.Intitule.IsEmpty() ? AnsiString(_strPtInterro) : cpt.Intitule;
    FieldByName(strfPC_IntituleLong)->AsString = cpt.IntituleLong;
    FieldByName(strfPC_CodeDevise)->AsInteger  = cpt.CodeDevise;
    FieldByName(strfPC_Cycle)->AsInteger       = (int)GetPropsCompte(cpt.Compte, bIntoCycleFinal);
    if(bIntoCycleFinal) {          FieldByName(strfPC_Flags)->AsInteger = PCFLAGS_COMPTE_CYCLE_FINAL;}
    else                 { ASSERT( FieldByName(strfPC_Flags)->AsInteger == PCFLAGS_AUCUN);}
    FieldByName(strfPC_Lettrable)->AsBoolean  = PosteDll.CompteEstDansPoste(cpt.Compte,7400);
    if(cpt.Supprime)    {          FieldByName(strfPC_Supprime)->AsBoolean = true;}
    else                 { ASSERT(!FieldByName(strfPC_Supprime)->AsBoolean);}
    if (NouveauCompteAuxiliaire)
      SetDrapeaux(true,PCDRAPEAUX_COMPTE_AUXILIAIRE);
    Post();
  } catch(Exception& e) {
    Cancel();
    delete tblPC;
    throw EUser(TAG(51), e);
  }
  return true;
 } /* TTablePC::CreerCompte() */


 /******************************************************************************\
 ************* TTablePC::CreerCompteCollectif() *********************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de créer un nouveau compte (sans débits/crédits     *
 * initiaux).                                                                   *
 *                                                                              *
 * Paramètres :                                                                 *
 *   cpt : Compte à créer (les débits et soldes sont ignorés).                  *
 *                                                                              *
 * Retour :                                                                     *
 *   TRUE si le compte n'existe pas déjà et a bien été créé; FALSE sinon.       *
 *                                                                              *
 * Note : Si une erreur quelconque survient, une exception est levée.           *
 \******************************************************************************/
 bool __fastcall TTablePC::CreerCompteCollectif( const CCompte& cpt, bool bCreate)
 {
   bool     bIntoCycleFinal; // TRUE si le compte à créer fait partie du cycle final
   bool     bTmp;            // Variable temporaire
   int AncienRecNo = RecNo;
   TStringField *tblPCCompte,*tblPCIntitule;
   TFilterRecordEvent AncienOnFilterRecord;
   AnsiString strCompte;

   ASSERT(State == dsBrowse);
   ASSERT( MasterSource==NULL);

   //////////////////////////////////////////////
   // Vérification de l'utilité de l'opération //
   //////////////////////////////////////////////
   // Vérifie qu'il n'y a pas d'interférence entre les différents comptes collectifs
   tblPCCompte = (TStringField *)FieldByName(strfPC_Compte);
   tblPCIntitule = (TStringField *)FieldByName(strfPC_Intitule);
   DisableControls();
   First();
   while( !Eof) {
     if ( EstUnCompteCollectif) {
       strCompte = tblPCCompte->AsString;
       if ( (bCreate && ((strCompte.Length() > cpt.Compte.Length() ? strCompte.Pos( cpt.Compte) : cpt.Compte.Pos( strCompte))==1))
           || ((strCompte != cpt.Compte) && (tblPCIntitule->AsString == cpt.Intitule)))
        {
          RecNo = AncienRecNo;
          EnableControls();
          return false;
        }
     }
     Next();
   }
   RecNo = AncienRecNo;
   EnableControls();

   if (cpt.Compte.IsEmpty() || (*cpt.Compte.c_str() < '1') || (*cpt.Compte.c_str() > /*'8'*/'9'))
     EICThrowInvalidArgument(TAG(52));

   ////////////////////////
   // Création du compte //
   ////////////////////////
   DisableControls();
   try {
      if ( bCreate) Insert();
               else Edit();

     ASSERT(FieldByName(strfPC_Visa)->AsInteger    == PCVISA_AUCUN);

     FieldByName(strfPC_TypeEnr)->AsInteger     = PCTYPEENR_COMPTE_COLLECTIF;
     tblPCCompte->AsString                      = cpt.Compte;
     tblPCIntitule->AsString                    = cpt.Intitule.IsEmpty() ? AnsiString(_strPtInterro) : cpt.Intitule;
     FieldByName(strfPC_IntituleLong)->AsString = cpt.IntituleLong;
     FieldByName(strfPC_CodeDevise)->AsInteger  = cpt.CodeDevise;
     FieldByName(strfPC_Cycle)->AsInteger       = (int)GetPropsCompte(cpt.Compte, bIntoCycleFinal);
     Post();

   } catch(Exception& e) {
     Cancel();
     EnableControls();
     throw EUser(TAG(53), e);
  }

   FilterID idFiltre;
   idFiltre = FID_NUL;
   PushFilter( idFiltre, EmptyStr);

   // Recherche tous les comptes auxiliaires et positionne le flag
   for( First(); !Eof; Next()) {
     if ( EstLeCollectifDe( tblPCCompte->AsString, cpt.Compte) && EstUnCompteNormal) {
       Edit();
       SetDrapeaux( true, PCDRAPEAUX_COMPTE_AUXILIAIRE);
       Post();
     }
   }

   PopFilter( idFiltre);
   AncienOnFilterRecord = OnFilterRecord;
    if (!CalculerDebitCreditCollectif(cpt.Compte))
      EICErreur(AnsiString("Impossible de calculer le solde du compte collectif '") + cpt.Compte + "'");
   OnFilterRecord = AncienOnFilterRecord;
   EnableControls();
   FlushBuffers();
   return(true);
 } /* TTablePC::CreerCompteCollectif() */




/*
  Cette fonction supprime le compte si possible et les écritures type et les notes sur les comptes.
  Renvoie true si le compte est supprimé.
*/
bool __fastcall TTablePC::SupprimerCompte(bool PoserUneQuestion,bool MessageSiNonSupprimable)
{
 int idsErr; // ID ressource d'erreur
 TStringField *tblPrmCompte,*tblNotesCompte;
 bool Supprime = false;
 CTable *tblHI = 0,*tblAdr = 0,*tblPrm = 0,*tblNotes = 0;
 AnsiString NumCompte(((TStringField *)FieldByName(strfPC_Compte))->AsString),strExercice;
 try
  {
    tblHI = new CTable(ttDossier,"$2h");
    tblAdr = new CTable(ttDossier,"$$3");
      tblHI->Open();
     tblAdr->Open();
     // A Faire :
     //.. Verifier que le compte n'est pas utilisé par des appli. annexes
     // .. qu'il n'est pas collectif ou centralisateur
          if( EstMouvemente    ) {idsErr = IDS_ERR_NE_PEUT_DETRUIRE_COMPTE_MOUVEMENTE; strExercice = "N";}
     else if( EstMouvementeNm1 ) {idsErr = IDS_ERR_NE_PEUT_DETRUIRE_COMPTE_MOUVEMENTE; strExercice = "N-1";}
     else if( EstMouvementeNm2 ) {idsErr = IDS_ERR_NE_PEUT_DETRUIRE_COMPTE_MOUVEMENTE; strExercice = "N-2";}
     else if( EstMouvementeNm3 ) {idsErr = IDS_ERR_NE_PEUT_DETRUIRE_COMPTE_MOUVEMENTE; strExercice = "N-3";}
     else if( EstMouvementeNm4 ) {idsErr = IDS_ERR_NE_PEUT_DETRUIRE_COMPTE_MOUVEMENTE; strExercice = "N-4";}
     else if( EstDejaMouvemente) {idsErr = IDS_ERR_NE_PEUT_DETRUIRE_COMPTE_MOUVEMENTE; strExercice = "N+1";}
     else if( tblHI->Locate( TTableHI::strfHI_Banque, NumCompte, TLocateOptions() << loCaseInsensitive))
                                        idsErr = IDS_ERR_NE_PEUT_DETRUIRE_COMPTE_UTILISE_DANS_ECHEANCE;
     else if ( tblAdr->Locate( "BanquePaiement", NumCompte, TLocateOptions() << loCaseInsensitive))
                                        idsErr = IDS_ERR_NE_PEUT_DETRUIRE_COMPTE_UTILISE_DANS_PARAMETRAGE;
     else                               idsErr = 0;
     tblAdr->Close();
      tblHI->Close();

     if( idsErr)
      {
        if (MessageSiNonSupprimable)
          EICErreur( EICFormat( MAKEINTRESOURCE( idsErr), NumCompte.c_str(),strExercice.c_str()));
      }
     else
     { // Il n'y a pas d'erreur
       // => Destruction physique du compte
       if (!PoserUneQuestion || EICQuestion((AnsiString("Vous allez supprimer le compte '") + NumCompte + "'.\nEtes-vous sûr de vouloir le supprimer ?").c_str(),"Attention",MB_DEFBUTTON2)) {
         // Suppression du compte dans les paramètrages des écrans de saisie
         tblPrm = new CTable(ttDossier,"$$y");
         tblPrm->Open();
         tblPrm->First();
         tblPrmCompte = (TStringField *)tblPrm->FieldByName("Compte");
         while( !tblPrm->Eof) {
           if ( tblPrmCompte->AsString==NumCompte) tblPrm->Delete();
                                              else tblPrm->Next();
         }
         tblPrm->Close();
          tblNotes = new CTable(ttDossier,"$$u");
          if (tblNotes->Exists)
            {
              tblNotes->Open();
              tblNotesCompte = (TStringField *)tblNotes->FieldByName("Compte");
              tblNotes->SetKey();
              tblNotes->KeyFieldCount = 1;
              tblNotesCompte->AsString = NumCompte;
              if (tblNotes->GotoKey())
                while (!tblNotes->Eof && (tblNotesCompte->AsString == NumCompte))
                  tblNotes->Delete();
              tblNotes->Close();
            }
          tblAdr->Open();
          if( tblAdr->FindKey( ARRAYOFCONST(( NumCompte)))) tblAdr->Delete();
          tblAdr->Close();
         // Suppression dans le plan comptable
         Delete();
         Supprime = true;
       }
     }
  }
 catch (Exception &e)
  {
    EICDisplayException(TAGL,e);
  }
 if (tblHI)
  delete tblHI;
 if (tblAdr)
  delete tblAdr;
 if (tblPrm)
  delete tblPrm;
 if (tblNotes)
  delete tblNotes;
 return Supprime;
}



bool __fastcall TTablePC::CalculerDebitCreditCollectif(const AnsiString &CompteCollectif)
{
  bool Resultat,EstDebiter,EstCrediter,EstDebiterSituation,EstCrediterSituation,EstDebiterTotal,EstCrediterTotal,EstSolderNm1,EstSolderNm2,EstSolderNm3,EstSolderNm4;
  TCurrencyField *tblPCDebit,*tblPCCredit,*tblPCDebitSituation,*tblPCCreditSituation,*tblPCDebitTotal,*tblPCCreditTotal,*tblPCSoldeNm1,*tblPCSoldeNm2,*tblPCSoldeNm3,*tblPCSoldeNm4;
  FilterID IDFiltre;
  Currency Debit,Credit,DebitSituation,CreditSituation,DebitTotal,CreditTotal,SoldeNm1,SoldeNm2,SoldeNm3,SoldeNm4;
  CSablier Sablier;

  ASSERT(!MasterSource);
  ASSERT(!OnFilterRecord);


  IDFiltre = FID_NUL;
  DisableControls();
  Resultat = false;
  try
    {
      PushFilter(IDFiltre,strfPC_Compte + "='" + CompteCollectif + "*'");
      First();
      Debit = Credit = DebitSituation = CreditSituation = DebitTotal = CreditTotal = SoldeNm1 = SoldeNm2 = SoldeNm3 = SoldeNm4 = 0.0;
      EstDebiter = EstCrediter = EstDebiterSituation = EstCrediterSituation = EstDebiterTotal = EstCrediterTotal = EstSolderNm1 = EstSolderNm2 = EstSolderNm3 = EstSolderNm4 = false;
      tblPCDebit = (TCurrencyField *)FieldByName(strfPC_Debit);
      tblPCCredit = (TCurrencyField *)FieldByName(strfPC_Credit);
      tblPCDebitSituation = (TCurrencyField *)FieldByName(strfPC_DebitSituation);
      tblPCCreditSituation = (TCurrencyField *)FieldByName(strfPC_CreditSituation);
      tblPCDebitTotal = (TCurrencyField *)FieldByName(strfPC_DebitTotal);
      tblPCCreditTotal = (TCurrencyField *)FieldByName(strfPC_CreditTotal);
      tblPCSoldeNm1 = (TCurrencyField *)FieldByName(strfPC_SoldeNm1);
      tblPCSoldeNm2 = (TCurrencyField *)FieldByName(strfPC_SoldeNm2);
      tblPCSoldeNm3 = (TCurrencyField *)FieldByName(strfPC_SoldeNm3);
      tblPCSoldeNm4 = (TCurrencyField *)FieldByName(strfPC_SoldeNm4);
      while(!Eof)
        {
          if (EstUnCompte)
            {
              Debit += tblPCDebit->AsCurrency;
              EstDebiter |= !tblPCDebit->IsNull;
              Credit += tblPCCredit->AsCurrency;
              EstCrediter |= !tblPCCredit->IsNull;
              DebitSituation += tblPCDebitSituation->AsCurrency;
              EstDebiterSituation |= !tblPCDebitSituation->IsNull;
              CreditSituation += tblPCCreditSituation->AsCurrency;
              EstCrediterSituation |= !tblPCCreditSituation->IsNull;
              DebitTotal += tblPCDebitTotal->AsCurrency;
              EstDebiterTotal |= !tblPCDebitTotal->IsNull;
              CreditTotal += tblPCCreditTotal->AsCurrency;
              EstCrediterTotal |= !tblPCCreditTotal->IsNull;
              SoldeNm1 += tblPCSoldeNm1->AsCurrency;
              EstSolderNm1 |= !tblPCSoldeNm1->IsNull;
              SoldeNm2 += tblPCSoldeNm2->AsCurrency;
              EstSolderNm2 |= !tblPCSoldeNm2->IsNull;
              SoldeNm3 += tblPCSoldeNm3->AsCurrency;
              EstSolderNm3 |= !tblPCSoldeNm3->IsNull;
              SoldeNm4 += tblPCSoldeNm4->AsCurrency;
              EstSolderNm4 |= !tblPCSoldeNm4->IsNull;
            }
          #ifdef _DEBUG
          else                                   //C'est soit le compte collectif en lui même soit un programme de travail qui est là par hazard
            if (EstUnCompteCollectif)
              ASSERT(((TStringField *)FieldByName(strfPC_Compte))->AsString == CompteCollectif);
            else
              ASSERT(EstUnProgrammeDeTravail);
          #endif
          Next();
        }
      VERIFY(AllerSurLeCompteCollectif(CompteCollectif));
      Edit();
      if (EstDebiter)
        tblPCDebit->AsCurrency = Debit;
      else
        tblPCDebit->Clear();
      if (EstCrediter)
        tblPCCredit->AsCurrency = Credit;
      else
        tblPCCredit->Clear();
      if (EstDebiterSituation)
        tblPCDebitSituation->AsCurrency = DebitSituation;
      else
        tblPCDebitSituation->Clear();
      if (EstCrediterSituation)
        tblPCCreditSituation->AsCurrency = CreditSituation;
      else
        tblPCCreditSituation->Clear();
      if (EstDebiterTotal)
        tblPCDebitTotal->AsCurrency = DebitTotal;
      else
        tblPCDebitTotal->Clear();
      if (EstCrediterTotal)
        tblPCCreditTotal->AsCurrency = CreditTotal;
      else
        tblPCCreditTotal->Clear();
      if (EstSolderNm1)
        tblPCSoldeNm1->AsCurrency = SoldeNm1;
      else
        tblPCSoldeNm1->Clear();
      if (EstSolderNm2)
        tblPCSoldeNm2->AsCurrency = SoldeNm2;
      else
        tblPCSoldeNm2->Clear();
      if (EstSolderNm3)
        tblPCSoldeNm3->AsCurrency = SoldeNm3;
      else
        tblPCSoldeNm3->Clear();
      if (EstSolderNm4)
        tblPCSoldeNm4->AsCurrency = SoldeNm4;
      else
        tblPCSoldeNm4->Clear();
      Post();
      PopFilter(IDFiltre);
      Resultat = true;
    }
  catch(Exception &e)
    {
      PopFilter(IDFiltre);
    }
  EnableControls();
  return Resultat;
}




/*
  Cette fonction calcule les soldes de tous les comptes collectifs.
*/
void __fastcall TTablePC::CalculerSoldesCollectifs()
{
  TStringField *tblPCCompte;
  int AncienRecNo;

  ASSERT(!Filtered);
  ASSERT(!MasterSource);

  tblPCCompte = (TStringField *)FieldByName(strfPC_Compte);
  First();
  while (!Eof)
    {
      if (EstUnCompteCollectif)
        {
          AncienRecNo = RecNo;
          CalculerDebitCreditCollectif(tblPCCompte->AsString);
          RecNo = AncienRecNo;

          ASSERT(EstUnCompteCollectif);
        }
      Next();
    }
}




void __fastcall TTablePC::SupprimerCompteCollectif( const AnsiString &strCompteCollectif)
{
  ASSERT( MasterSource==NULL);

  FilterID idFiltre;
  // Vérifie que le compte collectif existe
  if ( !AllerSurLeCompteCollectif( strCompteCollectif)) return;
  if ( !EstUnCompteCollectif) {
    EICThrowInvalidArgument( TAG( 54));
  }

  // Supprime le compte collectif
  DisableControls();
  Delete();

  // Retire le flag des comptes auxiliaires associés
  idFiltre = FID_NUL;
  PushFilter( idFiltre, EmptyStr);
  for( First(); !Eof; Next()) {
    if ( EstLeCollectifDe( FieldByName( strfPC_Compte)->AsString, strCompteCollectif)) {
      Edit();
      SetDrapeaux( false, PCDRAPEAUX_COMPTE_AUXILIAIRE);
      Post();
    }
  }

  // Remet la table dans sa forme initiale
  PopFilter( idFiltre);
  EnableControls();
}


 /******************************************************************************\
 ************* TTablePC::CreerCompteDlg() ***************************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de crééer un nouveau compte (sans débits/crédits    *
 * initiaux) à l'aide d'une boîte de dialogue appropriés.                       *
 *                                                                              *
 * Paramètres :                                                                 *
 *   tag           : Tag dans l'appelant                                        *
 *   bNoCptASaisir : TRUE si l'utilisateur DOIT saisir lui-même le N° du compte *
 *                   à créer; FALSE si le n° de compte à utiliser pour la       *
 *                   création est celui figurant en entrée dans le paramètre    *
 *                   cptCree (propriété Compte) - dans ce cas, ce n° de compte  *
 *                   ne doit alors pas être vide.                               *
 *   cptCree       : Retourne le nouveau compte créé (si la fonction retourne   *
 *                   FALSE, ce paramètre n'est pas modifié en sortie).          *
 *   hInstance     : Instance de l'appelant.                                    *
 *                                                                              *
 * Retour :                                                                     *
 *   TRUE si le compte a bien été créé; FALSE sinon (dans ce cas, c'est que     *
 * l'utilisateur a abandonné la création).                                      *
 \******************************************************************************/
 bool __fastcall TTablePC::CreerCompteDlg(EICTag   tag,
                                           bool     bNoCptASaisir,
                                           CCompte& cptCree,
                                           void*    hInstance /* = HInstance */)
 {
  bool           bCreated = false;        // TRUE si un compte a été effectivement créé

  ASSERT(bNoCptASaisir || !cptCree.Compte.IsEmpty());
  ASSERT(Active);
  ASSERT(!Filtered || Filter.Pos(szfPC_TypeEnr"=0"));

  ///////////////////////////////////////////////////
  // Affichage du dialogue de création d'un compte //
  ///////////////////////////////////////////////////
  try {
    if( bNoCptASaisir? DlgCreerCompte(false, this, EmptyStr) : DlgCreerCompte(this, cptCree))
    { // Un compte a été créé => Lecture du compte créé
      GetCompteCourant(cptCree);
      bCreated = true;
    }
  } catch(Exception& e) {
    EICDisplayException(tag, e, hInstance);
  }
  return bCreated;
 }

 /******************************************************************************\
 ************* TTablePC::CreerCompteStandard() **********************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette procédure permet de créer un compte standard (sans débits/crédits   *
 * initiaux) s'il n'existe pas déjà et de se positionner dessus.                *
 *                                                                              *
 * Paramètres :                                                                 *
 *   tag       : Tag de l'appelant                                              *
 *   epccs     : Une valeur PCCPTSTANDARD_* qui identifie le compte à créer.    *
 *   hInstance : Instance de l'appelant.                                        *
 *                                                                              *
 * Note : Si une erreur survient, une exception est levée.                      *
 \******************************************************************************/
void __fastcall TTablePC::CreerCompteStandard(EICTag             tag,
                                               const AnsiString &Compte,
                                               const AnsiString &Libelle,
                                                void*              hInstance /* = HInstance */)
{
  ASSERT(!Filtered);

  if(!AllerSurLeCompte(Compte))
  { // Le compte n'existe pas => On le créé
    CCompte cptStandard(Compte.c_str(),Libelle.c_str());

    ASSERT(!cptStandard.RANDetaille);
    ASSERT(!cptStandard.Supprime);

    CreerCompte(cptStandard);
  }
}


 /******************************************************************************\
 ************* TTablePC::CreerComptesArrondis() *********************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette procédure permet de créer les comptes de gestion des erreurs        *
 * d'arrondis de devises avec l'Euro.                                           *
 *                                                                              *
 * Note : Si une erreur survient, une exception est levée.                      *
 \******************************************************************************/
 void __fastcall TTablePC::CreerComptesArrondis()
 {
  ASSERT(State == dsBrowse);
  ASSERT(!Filtered);
  ASSERT(!OnFilterRecord);

  ASSERT( CEditCompte::CM_CompleteCompte); // Ce membre devrait toujours être initialisé

  cm_strCptPerteArrondis = CEditCompte::CM_CompleteCompte( "6688");
  CCompte cptArr(cm_strCptPerteArrondis.c_str(), _CodePays==CP_FRANCE ? "Charges d'arrondis de conver. euro" : "Charges d'arrondis de conversion");
  CreerCompte(cptArr);         // Création des comptes d'arrondis

  cm_strCptProfiArrondis = CEditCompte::CM_CompleteCompte( "7688");
  cptArr.Compte   = cm_strCptProfiArrondis.c_str();
  cptArr.Intitule = _CodePays==CP_FRANCE ? "Produits d'arrondis de conver. euro" : "Produits d'arrondis de conversion";
  CreerCompte(cptArr);
 }


 /******************************************************************************\
 ************* TTablePC::CreerCompteRepriseDeDotation() *************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de retourner un compte du PC.                       *
 *                                                                              *
 * Paramètres :                                                                 *
 *   strCompte : Compte à rechercher dans le PC                                 *
 *                                                                              *
 * Retour :                                                                     *
 *   TRUE si le compte a été trouvé dans le PC (auquel cas, l'enregistrement    *
 * courant est le compte lui-même); FALSE sinon (dans ce cas, l'enregistrement  *
 * courant est un enregistrement quelconque).                                   *
 \******************************************************************************/
 AnsiString __fastcall TTablePC::CreerCompteRepriseDeDotation(const AnsiString& strCptDotation,
                                                               bool              bCreerCptReprise) /* = true */
 {
  const char* pcszCptDotation; // Compte de dotation

  ASSERT(State == dsBrowse);
  ASSERT(!Filtered);
  ASSERT(!OnFilterRecord);
  ASSERT(!strCptDotation.IsEmpty());
  ASSERT(strCptDotation.Length() <= 13);


  if(bCreerCptReprise && (*(pcszCptDotation = strCptDotation.c_str()) == '6'))
  { ///////////////////////////////////////////////////////////////////////////////////////////////
    // Il faut créer un compte de reprise correspondant au compte de dotation passé en paramètre //
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // => Création du n° de compte de reprise correspondant au compte de dotation
    char szCptReprise[ 20];

    strcpy(szCptReprise + 1, pcszCptDotation + 1); *szCptReprise = '7';

    // => Création du compte
    CreerCompte(CCompte(szCptReprise, NULL));

    // => Retour du compte de reprise attendu
    return(AnsiString(szCptReprise));
  }
  else
  { // Le compte de reprise correspondant au compte de dotation n'a pas besoin d'être créé
    // ou bien le compte de dotation n'est pas un compte de dotation (de classe '6')
    // => Retour du compte d'origine
    return(strCptDotation);
  }
 } /* TTablePC::CreerCompteRepriseDeDotation() */


 /******************************************************************************\
 ************* TTablePC::ModifierCompte() ***************************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette procédure permet de modifier les caractéristiques (sauf les visas,  *
 * drapeaux, débit/crédit et soldes N-x) d'un compte.                           *
 *                                                                              *
 * Paramètres :                                                                 *
 *   cpt : Compte à mettre à jour dans la table.                                *
 \******************************************************************************/
 void __fastcall TTablePC::ModifierCompte(const CCompte& cpt)
 {
  ASSERT(!IsEmpty());
  ASSERT(State == dsBrowse);


  try {
    if(!AllerSurLeCompte(cpt.Compte))    // Localisation du compte
      EICThrowInvalidArgument(TAG(60));  // Compte non trouvé
    DisableControls();
    Edit();
    FieldByName(strfPC_Intitule)->AsString     = cpt.Intitule;
    FieldByName(strfPC_IntituleLong)->AsString = cpt.IntituleLong;
    FieldByName(strfPC_CodeDevise)->AsString   = cpt.CodeDevise;
    FieldByName(strfPC_Lettrable)->AsBoolean   = cpt.RANDetaille;
    FieldByName(strfPC_Supprime)->AsBoolean    = cpt.Supprime;
    FieldByName(strfPC_CompteAbrege)->AsString = cpt.CompteAbrege;
    Post();
    EnableControls();
    FlushBuffers();
  } catch(Exception& e) {
    Cancel();
    EnableControls();
    throw EUser(TAG(61), e);
  }
}


 /******************************************************************************\
 ************* TTablePC::RAZSoldes() ********************************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet d'effacer les soldes d'un exercice du PC.           *
 *                                                                              *
 * Paramètres :                                                                 *
 *   tag         : Tag de l'opération dans l'appelant.                          *
 *   eIDExercice : ID de l'exercice pour lequel effacer les soldes.             *
 *   pbarre      : Barre de progression à utiliser (NULL pour aucune)           *
 *   hInstance   : Instance de l'appelant                                       *
 *                                                                              *
 * Notes : * Sur l'exercice N, la fonction efface aussi les visas.              *
 *         * Si une erreur survient pendant l'effacement des soldes, une        *
 *           exception EUser est levée avec la tag passé en paramètre.          *
 \******************************************************************************/
 void __fastcall TTablePC::RAZSoldes(EICTag  tag,
                                      int     eIDExercice,
                                      CBarre* pbarre,
                                      int     hInstance) // = (int)HInstance
 {
  FilterID fidComptes;  // Filtre des comptes
  bool     bExerciceN;  // TRUE s'il faut RAZ les soldes de l'exercice N
  TField*  pfldToRAZ1;  // Champ "Solde devise d'origine N-x" ou "Débit N"  à RAZ
  TField*  pfldToRAZ2;  // Champ  "Solde devise dossier N-x"  ou "Crédit N" à RAZ
  TField*  pfldVisas;   // Champ "Visa sur l'exercice N"
  TCurrencyField *tblPCDebitTotal,*tblPCCreditTotal,*tblPCDebitSituation,*tblPCCreditSituation;

  ASSERT(State == dsBrowse);
  ASSERT(!Filtered);
  
  fidComptes = FID_NUL;
  try {
    switch(eIDExercice)
    {
      case IDEXERCICE_N :
        pfldToRAZ1 = FieldByName(strfPC_Debit);
        pfldToRAZ2 = FieldByName(strfPC_Credit);
        pfldVisas  = FieldByName(strfPC_Visa);
        tblPCDebitTotal = (TCurrencyField *)FieldByName(strfPC_DebitTotal);
        tblPCCreditTotal = (TCurrencyField *)FieldByName(strfPC_CreditTotal);
        tblPCDebitSituation = (TCurrencyField *)FieldByName(strfPC_DebitSituation);
        tblPCCreditSituation = (TCurrencyField *)FieldByName(strfPC_CreditSituation);
        bExerciceN = true;
        break;
      case IDEXERCICE_Nm1 :
        pfldToRAZ1 = NULL;
        pfldToRAZ2 = FieldByName(strfPC_SoldeNm1);
        bExerciceN = false;
        break;
      case IDEXERCICE_Nm2 :
        pfldToRAZ1 = NULL;
        pfldToRAZ2 = FieldByName(strfPC_SoldeNm2);
        bExerciceN = false;
        break;
      case IDEXERCICE_Nm3 :
        pfldToRAZ1 = NULL;
        pfldToRAZ2 = FieldByName(strfPC_SoldeNm3);
        bExerciceN = false;
        break;
      case IDEXERCICE_Nm4 :
        pfldToRAZ1 = NULL;
        pfldToRAZ2 = FieldByName(strfPC_SoldeNm4);
        bExerciceN = false;
        break;
      default :
        ASSERT(false);
    }


    //////////////////////////////////
    // RAZ des soldes de l'exercice //
    //////////////////////////////////
    // Filtrage du PC pour ne conserver que les comptes
    #if PCTYPEENR_COMPTE != 0
     #error *** L'enum PCTYPEENR_COMPTE ne vaut plus zéro: revoir le code suivant... ***
    #endif
    #if PCTYPEENR_COMPTE_COLLECTIF != 2
     #error *** L'enum PCTYPEENR_COMPTE_COLLECTIF ne vaut plus zéro: revoir le code suivant... ***
    #endif
    PushFilter(fidComptes, szfPC_TypeEnr "=0 OR " szfPC_TypeEnr "=2");

    // MAJ de la barre de progression
    if(pbarre)
      pbarre->Max = RecordCount;

    // RAZ des soldes
    First();
    while(!Eof)
    {
      Edit();
      if (pfldToRAZ1)
        pfldToRAZ1->Clear();
      pfldToRAZ2->Clear();
      if(bExerciceN)
      {
        pfldVisas->AsInteger = PCVISA_AUCUN;
        tblPCDebitTotal->Clear();
        tblPCCreditTotal->Clear();
        tblPCDebitSituation->Clear();
        tblPCCreditSituation->Clear();
      }
      Next();
      if(pbarre)
        (*pbarre)++;
    }

    // Validation des modifications
    FlushBuffers();

    // Levée du filtre
    PopFilter(fidComptes); ASSERT(!Filtered);
  } catch(Exception& e) {
    Cancel();
    PopFilter(fidComptes); ASSERT(!Filtered);
    throw EUser(tag, e);
  }
 } /* TTablePC::RAZSoldes() */


 /******************************************************************************\
 ************* TTablePC::ImporterCompte() ***************************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet d'importer un compte dans le PC.                    *
 *                                                                              *
 * Paramètres :                                                                 *
 *   cpt         : Compte à importer (sur l'exercice courant, le compte ne doit *
 *                 pas déjà exister).                                           *
 *   eIDExercice : ID de l'exercice dans lequel le compte doit être importé.    *
 *                                                                              *
 * Notes : * Selon l'ID de l'exercice dans lequel importer le compte, la        *
 *           fonction "voit" le compte à importer d'une manière appropriée (par *
 *           ex., pour l'exercice N - x, la propriété "Lettrable" est ignorée). *
 *         * Une exception peut être levée par la fonction, auquel cas,         *
 *           l'appelant doit se charger de l'affichage du message d'erreur.     *
 *         * Si on importe un compte pour l'exercice N et que le compte existe  *
 *           déjà, seul son intitulé peut être mis à jour s'il est inconnu.     *
 *         * Le code de la devise du compte à importer est ignoré (i.e. les     *
 *           soldes N-x ou masses Débit/Crédit N doivent être exprimés dans la  *
 *           devise appropriée à l'exercice dans lequel importer le compte.)    *
 \******************************************************************************/
/* void __fastcall TTablePC::ImporterCompte(const CCompte& cpt,
                                           int            eIDExercice)
 {
  EICTag  tag;
  bool    bIntoCycleFinal; // TRUE si le compte à créer fait partie du cycle final
  bool    bRANDetaille;    // TRUE si le compte à importer doit, par défaut, être repris en détail pour l'A Nouveau
  bool    bExistYet;       // TRUE si le compte existe déjà dans le plan comptable
  TStringField* pfldIntitule;    // Champ "Intitulé" du PC
  TCurrencyField* pfldSoldeNmX;    // Champ  "Solde N-x devise dossier"  du PC

  #ifdef _DEBUG
    ASSERT(State == dsBrowse);
    ASSERT((eIDExercice == IDEXERCICE_COURANT) ||
            (eIDExercice == IDEXERCICE_N) ||
            (eIDExercice == IDEXERCICE_Nm1) ||
            (eIDExercice == IDEXERCICE_Nm2) ||
            (eIDExercice == IDEXERCICE_Nm3) ||
            (eIDExercice == IDEXERCICE_Nm4));
    ASSERT(!cpt.Compte.IsEmpty());
    if(eIDExercice != IDEXERCICE_COURANT)
    { // Pré-conditions sur un compte à importer
      if(cpt.Intitule.IsEmpty())
        EICAttention(("Erreur: Intitulé du Compte '" + cpt.Compte +"' est vide.\nAssert va être levée..."));
      ASSERT(!cpt.Intitule.IsEmpty());
    }
  #endif


  ///////////////////////////////////////////
  // Vérification de l'existence du compte //
  ///////////////////////////////////////////
  bExistYet = AllerSurLeCompte(cpt.Compte);

  ASSERT(!bExistYet || (eIDExercice != IDEXERCICE_COURANT)); // Sur exercice courant, le cpt ne doit pas déjà exister !

  ////////////////////////
  // Création du compte //
  ////////////////////////
  try {
    tag          = TAG(70);
    pfldIntitule = (TStringField *)FieldByName(strfPC_Intitule);
    if(bExistYet)
    { // => On va MAJ (i.e. importer sur un exercice spécifique) le compte existant
      ASSERT(FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_COMPTE);
      tag = TAG(71);
      Edit();

      //
      // MAJ des montants (seulement pour des comptes importés sur N - x
      // car les montants sur N et N+1 sont renseignés via les écritures dans l'historique.
      // Pour importer un compte sur N, il faut passer par une saisie de journal (i.e. une écriture))
      //
      switch(eIDExercice)
      {
        case IDEXERCICE_Nm1 :
          pfldSoldeNmX  = (TCurrencyField *)FieldByName(strfPC_SoldeNm1);
          if(cpt.EstMouvementeNm1)
            pfldSoldeNmX->AsCurrency = cpt.SoldeNm1;
          else
            pfldSoldeNmX->Clear();
          goto MAJLibelle;
        case IDEXERCICE_Nm2 :
          pfldSoldeNmX  = (TCurrencyField *)FieldByName(strfPC_SoldeNm2);
          if(cpt.EstMouvementeNm2)
            pfldSoldeNmX->AsCurrency = cpt.SoldeNm2;
          else
            pfldSoldeNmX->Clear();
          goto MAJLibelle;
        case IDEXERCICE_Nm3 :
          pfldSoldeNmX  = (TCurrencyField *)FieldByName(strfPC_SoldeNm3);
          if(cpt.EstMouvementeNm3)
            pfldSoldeNmX->AsCurrency = cpt.SoldeNm3;
          else
            pfldSoldeNmX->Clear();
          goto MAJLibelle;
        case IDEXERCICE_Nm4 :
          pfldSoldeNmX  = (TCurrencyField *)FieldByName(strfPC_SoldeNm4);
          if(cpt.EstMouvementeNm4)
            pfldSoldeNmX->AsCurrency = cpt.SoldeNm4;
          else
            pfldSoldeNmX->Clear();
          goto MAJLibelle;
        case IDEXERCICE_N :
          MAJLibelle:
          if((pfldIntitule->AsString == _strPtInterro) || pfldIntitule->IsNull)
          { // MAJ de l'intitulé (court) du compte car il était inconnu auparavant
            ASSERT(!cpt.Intitule.IsEmpty());
            pfldIntitule->AsString = cpt.Intitule;
          }
          break;
        default:
          ASSERT(false);
      }
    }
    else
    { // => On va importer/créer un nouveau compte
      tag = TAG(72);
      Insert();

      ASSERT(FieldByName(strfPC_Visa)->AsInteger == PCVISA_AUCUN);
      ASSERT(FieldByName(strfPC_Debit)->IsNull);
      ASSERT(FieldByName(strfPC_Credit)->IsNull);
      ASSERT(FieldByName(strfPC_SoldeNm1)->IsNull);
      ASSERT(FieldByName(strfPC_SoldeNm2)->IsNull);
      ASSERT(FieldByName(strfPC_SoldeNm3)->IsNull);
      ASSERT(FieldByName(strfPC_SoldeNm4)->IsNull);
      ASSERT(FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_COMPTE);


      //
      // Lecture des propriétés de cycle du compte
      //
      FieldByName(strfPC_Cycle)->AsInteger = (int)GetPropsCompte(cpt.Compte, bIntoCycleFinal);
      if(bIntoCycleFinal)
      { // Ce compte doit figurer dans le cycle final
        FieldByName(strfPC_Flags)->AsInteger = PCFLAGS_COMPTE_CYCLE_FINAL;
      }
      else
      { // Par défaut, un compte n'a aucune particularité
        ASSERT(FieldByName(strfPC_Flags)->AsInteger == PCFLAGS_AUCUN);
      }


      //
      // Propriété "RAN Détaillé" du compte à importer/créer
      //
      if((bRANDetaille && (eIDExercice != IDEXERCICE_COURANT)) ||
          (cpt.RANDetaille && (eIDExercice == IDEXERCICE_COURANT))
        )
      { // Le compte à importer spécifiquement dans un exercice est lettrable par défaut ou
        // le compte à créer dans l'exercice courant (N) doit être créé "Lettrable"
        FieldByName(strfPC_Lettrable)->AsBoolean = true;
      }
      else
      { // Par défaut, un compte n'est pas "Lettrable"
        ASSERT(!FieldByName(strfPC_Lettrable)->AsBoolean);
      }


      //
      // Le compte doit-il être créé (sur l'exercice courant N) comme supprimé ?
      //
      if(cpt.Supprime && (eIDExercice == IDEXERCICE_COURANT))
      {
        FieldByName(strfPC_Supprime)->AsBoolean = true;
      }
      else
      { // Par défaut, un compte est créé comme "Non supprimé"
        ASSERT(!FieldByName(strfPC_Supprime)->AsBoolean);
      }


      //
      // Initialisation du compte à créer
      //
      // Initialisation des soldes sur N-x
      switch(eIDExercice)
      { case IDEXERCICE_Nm1 :
          if(cpt.EstMouvementeNm1)
            FieldByName(strfPC_SoldeNm1)->AsCurrency = cpt.SoldeNm1;
          break;
        case IDEXERCICE_Nm2 :
          if(cpt.EstMouvementeNm2)
            FieldByName(strfPC_SoldeNm2)->AsCurrency = cpt.SoldeNm2;
          break;
        case IDEXERCICE_Nm3 :
          if(cpt.EstMouvementeNm3)
            FieldByName(strfPC_SoldeNm3)->AsCurrency = cpt.SoldeNm3;
          break;
        case IDEXERCICE_Nm4 :
          if(cpt.EstMouvementeNm4)
            FieldByName(strfPC_SoldeNm4)->AsCurrency = cpt.SoldeNm4;
          break;
        default:
          ASSERT(false);
      }

      // Autres caractéristiques
      FieldByName(strfPC_Compte)->AsString       = cpt.Compte;
      FieldByName(strfPC_IntituleLong)->AsString = cpt.IntituleLong;
      pfldIntitule->AsString                      = cpt.Intitule.IsEmpty() ? AnsiString(_strPtInterro) : cpt.Intitule;
    }


    //
    // Création/MAJ physique du compte
    //
    tag = TAG(73);
    Post();
  } catch(Exception& e) {
    Cancel();
    throw EUser(tag, e);
  }
 } /* TTablePC::ImporterCompte() */


 /******************************************************************************\
 ************* TTablePC::GetCompteCourant() *************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de retourner le compte courant du PC.               *
 *                                                                              *
 * Paramètres :                                                                 *
 *   cptCourant : Retourne le compte courant (avec ses caractéristiques sur N   *
 *                uniquement)                                                   *
 \******************************************************************************/
 void __fastcall TTablePC::GetCompteCourant(CCompte& cptCourant)
 {
  TField* pfldTmp; // Un champ de la table

  ASSERT(Active);
  ASSERT(FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_COMPTE);

  ////////////////////////////////////////////////////
  // Lecture des caractéristiques du compte courant //
  ////////////////////////////////////////////////////
  cptCourant.Compte       = FieldByName(strfPC_Compte)->AsString;
  cptCourant.CompteAbrege = FieldByName(strfPC_CompteAbrege)->AsString;
  cptCourant.Intitule     = FieldByName(strfPC_Intitule)->AsString;
  cptCourant.IntituleLong = FieldByName(strfPC_IntituleLong)->AsString;
  cptCourant.CodeDevise   = FieldByName(strfPC_CodeDevise)->AsInteger;
  cptCourant.RANDetaille  = FieldByName(strfPC_Lettrable)->AsBoolean;
  cptCourant.Supprime     = FieldByName(strfPC_Supprime)->AsBoolean;

  if((pfldTmp = FieldByName(strfPC_Debit))->IsNull)
    cptCourant.Debit = (int)0;
  else
    cptCourant.Debit = pfldTmp->AsCurrency;
  if((pfldTmp = FieldByName(strfPC_Credit))->IsNull)
    cptCourant.Credit = (int)0;
  else
    cptCourant.Credit = pfldTmp->AsCurrency;
 }



/******************************************************************************\
************* TTablePC::ViserCompteCourant() ***********************************
********************************************************************************
*                                                                              *
*    Cette fonction permet de viser ou déviser le compte courant.              *
*                                                                              *
* Paramètres :                                                                 *
*   bViser     : TRUE/FALSE s'il faut viser/déviser le compte courant.         *
*   bVisaFinal : TRUE si le visa du cyle final doit aussi être positionné ou   *
*                doit aussi sauter.                                            *
*                                                                              *
* Notes : - Si le compte n'est pas un compte du cycle final, le paramètre      *
*           bVisaFinal est ignoré.                                             *
*         - Poser un visa ordinaire fait sauter le visa final.                 *
*         - Poser/Supprimer un visa final implique de poser/Supprimer le visa  *
*           ordinaire.                                                         *
\******************************************************************************/
void __fastcall TTablePC::ViserCompteCourant(bool bViser,bool bVisaFinal)
{
  TField* pfldVisas; // Champs des visas du compte courant
  int     bCptFinal; // != 0 si ce compte fait partie du cycle final
  int     fOldVisas; // Anciens  visas du compte
  int     fNewVisas; // Nouveaux   "   "    "

  ASSERT(State == dsBrowse);

  /////////////////////////////////////////
  // Lecture des visas actuels du compte //
  /////////////////////////////////////////
  fOldVisas = (pfldVisas = FieldByName(strfPC_Visa))->AsInteger;
  bCptFinal = (FieldByName(strfPC_Flags)->AsInteger & PCFLAGS_COMPTE_CYCLE_FINAL);

  ////////////////////
  // Calcul du visa //
  ////////////////////
  if(bViser)
  { // Détermination du visa à poser
    if(bVisaFinal)
    { // On veut poser un visa du cycle final
      if(bCptFinal)
      { // Ce compte est bien paramétré dans le cycle final
        // => On va viser le cycle final ET EVENTUELLEMENT le cycle ordinaire (depuis le cycle final)
        if(fOldVisas & PCVISA_ORDINAIRE_PAR_ORDINAIRE)
          fNewVisas = (PCVISA_ORDINAIRE_PAR_ORDINAIRE | PCVISA_FINAL_PAR_FINAL);
        else
          fNewVisas = (PCVISA_ORDINAIRE_PAR_FINAL     | PCVISA_FINAL_PAR_FINAL);
      }
      else
      { // Ce compte est dans un cycle ordinaire
        // => On pose le visa du cycle ordinaire (depuis le cycle final): L'éventuel visa final saute automatiquement
        if(fOldVisas & PCVISA_ORDINAIRE_PAR_ORDINAIRE)
          fNewVisas = PCVISA_ORDINAIRE_PAR_ORDINAIRE;
        else
          fNewVisas = PCVISA_ORDINAIRE_PAR_FINAL;
      }
    }
    else
    { // On pose un visa sur le cycle ordinaire seulement
      // => Pose du visa ordinaire (depuis le cycle ordinaire - si le compte fait partie du cycle final, les visas finaux sautent)
      fNewVisas = PCVISA_ORDINAIRE_PAR_ORDINAIRE;
    }
  }
  else
  { // On veut déviser le compte
    if(bVisaFinal && bCptFinal)
    { // On dévise un compte du cycle final depuis le cycle final
      if(fOldVisas & PCVISA_ORDINAIRE_PAR_ORDINAIRE)
        fNewVisas = PCVISA_ORDINAIRE_PAR_ORDINAIRE;
      else
        fNewVisas = PCVISA_AUCUN;
    }
    else
    { // On dévise un compte quelconque depuis un cycle ordinaire ou un compte non final depuis un cycle quelconque
      // => On dévise entièrement le compte
      fNewVisas = PCVISA_AUCUN;
    }
  }
  Edit();
  pfldVisas->AsInteger = fNewVisas;              // MAJ du visa
  Post();
} /* TTablePC::ViserCompteCourant() */


 /******************************************************************************\
 ************* TTablePC::ModifierCompteCourantDlg() *****************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de modifier le compte courant par l'intermédiaire   *
 * d'une boîte de dialogue appropriée.                                          *
 *                                                                              *
 * Paramètres :                                                                 *
 *   tag       : Tag de l'opération                                             *
 *   hInstance : Instance de l'appelant                                         *
 *                                                                              *
 * Retour :                                                                     *
 *   TRUE si le compte courant a été modifié; FALSE sinon (i.e. l'utilisateur   *
 * a abandonné le dialogue de modification).                                    *
 \******************************************************************************/
 bool __fastcall TTablePC::ModifierCompteCourantDlg(EICTag tag,
                                                     void*  hInstance) // = HInstance
 {
  bool           bModified = false;       // TRUE si le compte courant est modifié

  ASSERT(Active && (State == dsBrowse) && (!Filtered || Filter.Pos(szfPC_TypeEnr"=0")));
  ASSERT(!IsEmpty());

  try {
    // Vérification de la possibilité de modification du compte
    if(FieldByName(strfPC_TypeEnr)->AsInteger != PCTYPEENR_COMPTE)
      EICThrowInvalidArgument(TAG(80));

    // Modification du compte
    bModified = DlgCreerCompte(true, this, FieldByName(strfPC_Compte)->AsString);
  } catch(Exception& e) {
    EICDisplayException(tag, e, hInstance);
  }
  return bModified;
 }



 /******************************************************************************\
 ************* TTablePC::FiltrerCycle() *****************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de filtrer le PC selon un cycle donné.              *
 *                                                                              *
 * Paramètres :                                                                 *
 *   eCycle            : Code du cycle à filtrer.                               *
 *   bVoirPT           : TRUE pour ne pas filtrer les Prgm de Travail du cycle. *
 *   bVoirComptesVises : TRUE si le filtre ne doit pas exclure les comptes visés*
 *                       du cycle.                                              *
 *   FilteredATrue     : TRUE pour forcer le Filtered, FALSE pour ne pas changer*
 *                       le Filtered.                                           *
 *                                                                              *
 * Attention : Lorsque le cycle Examen Critique, Final ou Etats Financiers est  *
 *             filtré, on voit tous les comptes du PC et les comptes visés      *
 *             ordinaires mais non visés final sont "assimilés non visés" pour  *
 *             le cycle en question.                                            *
 \******************************************************************************/
 void __fastcall TTablePC::FiltrerCycle(enum CODE_CYCLE eCycle,
                                        bool            bVoirPT,
                                        bool            bVoirComptesVises,
                                        bool            FilteredATrue)
 {
  #if(PCTYPEENR_COMPTE != 0 )
   #error *** PCTYPEENR_COMPTE != 0 : Valeur de constante modifiée => Revoir le code suivant... ***
  #endif
  AnsiString strNewFilter((const char*)(bVoirPT ? NULL : szfPC_TypeEnr "=0 "));  // Nouveau filtre sur le PC

  ASSERT((eCycle >= CYC_FIRST) && (eCycle <= CYC_LAST));


  //////////////////////
  // Calcul du filtre //
  //////////////////////
  switch(eCycle)
  { // Pour les cycles Examen Critique, Final et Etats Financiers, tous les comptes sont affichés
    // => Pas de filtrage sur le cycle
    case CYC_EX_CRITIQUE :
    case CYC_ETATS_FI    :
      // => Filtrage des comptes non visés
      if(!bVoirComptesVises)
      { // L'utilisateur ne veut pas voir les comptes visés du cycle final
        // => On lui montre ceux qui sont non visés et
        //                  ceux du cycle final qui ne sont visés que dans leur cycle ordinaire
        #if (PCVISA_AUCUN != 0 ) || ((PCVISA_ORDINAIRE_PAR_ORDINAIRE|PCVISA_ORDINAIRE_PAR_FINAL) != 3)
         #error *** PCVISA_AUCUN != 0 : Valeur de constante modifiée => Revoir le code suivant... ***
        #endif
        if(!bVoirPT)
          strNewFilter += "AND"; // Filtre déjà composé pour ne retenir que les comptes

        strNewFilter += "(" szfPC_Visa "=0"            // Compte non visé
                          " OR("      szfPC_Flags "=1" // Compte du cycle final
                              " AND " szfPC_Visa "<=3" // ...seulement visé dans son cycle ordinaire
                              ")"
                        ")";
      }
      break;

    // Cycle ordinaire
    default :
      if(!bVoirPT)
        strNewFilter += "AND"; // Filtre déjà composé pour ne retenir que les comptes

      // Filtrage du cycle
      strNewFilter += " " szfPC_Cycle "=" + AnsiString((int)eCycle);

      // Filtrage des comptes non visés
      if(!bVoirComptesVises)
      { // L'utilisateur ne veut pas voir les comptes visés de ce cycle
        // => On ne lui montre que ceux qui sont non visés (dans ce cyle ou dans le cycle final)
        #if (PCVISA_AUCUN != 0 )
         #error *** PCVISA_AUCUN != 0 : Valeur de constante modifiée => Revoir le code suivant... ***
        #endif
        strNewFilter += " AND " szfPC_Visa "=0";
      }
      break;
  }


  /////////////////////////////////////
  // Mise en place du nouveau filtre //
  /////////////////////////////////////
  Filter = strNewFilter;
  if (FilteredATrue)
    Filtered = true;
 } /* TTablePC::FiltrerCycle() */


 /*----------------------------------------------------------------------------*\
 ------------- TTablePC::OuvrirTableCycles() ------------------------------------
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette procédure permet d'ouvrir - en lecture seule - la table commune de  -
 - définition des cycles et des propriétés par défaut des comptes.              -
 -                                                                              -
 - Paramètres :                                                                 -
 -   ptblCycles : Table des cycles à instancier et à ouvrir (NULL en entrée).   -
 \*----------------------------------------------------------------------------*/
 void __fastcall TTablePC::OuvrirTableCycles(CTable*& ptblCycles)
 {
  ASSERT(ptblCycles == NULL);


  try {
    //////////////////////////////////////
    // Ouverture de la table des cycles //
    //////////////////////////////////////
    // Instanciation de la table
    ptblCycles = new CTable("Racines", ttCommun, this);

    // Ouverture
    ASSERT(ptblCycles->DatabaseName == "EIC_COMMUN");
    ASSERT(!ptblCycles->Active && !ptblCycles->Filtered);
    ptblCycles->ReadOnly = true;
    ptblCycles->Open();
  } catch(Exception& e) {
    delete ptblCycles;
    ptblCycles = NULL;
    throw EUser(TAG(90), e);
  }
 }



 /*============================================================================*\
 ============= TTablePC::FermerTableCycles() ====================================
 ================================================================================
 =                                                                              =
 =    Cette procédure permet de refermer la table commune de définition des     =
 = cycles et des propriétés par défaut des comptes.                             =
 =                                                                              =
 = Paramètres :                                                                 =
 =   ptblCycles : Table des cycles à refermer (Si NULL en entrée, la procédure  =
 =                ne fait rien; sinon, elle ferme la table et initialisé à NULL en entrée).    =
 \*============================================================================*/
 void __fastcall TTablePC::FermerTableCycles(CTable*& ptblCycles)
 {
  ASSERT((ptblCycles == NULL) || ptblCycles->Active);


  try {
    //////////////////////////////////////
    // Fermeture de la table des cycles //
    //////////////////////////////////////
    delete ptblCycles; // Fermeture automatique
    ptblCycles = NULL;
  } catch(Exception& e) {
    delete ptblCycles;
    ptblCycles = NULL;
    throw EUser(TAG(100), e);
  }
 }



 /*============================================================================*\
 ============= TTablePC::GetPropsUnCompte() =====================================
 ================================================================================
 =                                                                              =
 =    Cette fonction permet de récupérer les propriétés d'un compte i.e.        =
 = d'indiquer à quel cycle un compte appartient, si ce compte doit figurer dans =
 = le cycle final et s'il est lettrable par défaut.                             =
 =                                                                              =
 = Paramètres :                                                                 =
 =   strCompte       : Compte dont on veut connaître le cycle.                  =
 =   bIntoCycleFinal : Retourne TRUE si le compte doit aussi figurer dans le CF =
 =                                                                              =
 = Retour :                                                                     =
 =   Le code du cycle auquel le compte appartient (une valeur CYC_*).           =
 \*============================================================================*/
 /*enum CODE_CYCLE __fastcall TTablePC::GetPropsUnCompte(CTable*           ptblCycles,
                                                        const AnsiString& strCompte,
                                                        bool&             bIntoCycleFinal)
 {
  enum RACINESTypeEnr {
    RACINESTYPEENR_RACINE_CYCLE_STANDARD = 0, // Donne le cycle standard des comptes de cette classe
    RACINESTYPEENR_RACINE_CYCLE_FINAL    = 1, // Les comptes de cette racine sont à viser aussi dans le cycle final

    RACINESTYPEENR_FIRST = RACINESTYPEENR_RACINE_CYCLE_STANDARD,
    RACINESTYPEENR_LAST  = RACINESTYPEENR_RACINE_CYCLE_FINAL
  };

  #define szfCYCLES_RACINE  "Racine"  // Racine
  #define szfCYCLES_TYPEENR "TypeEnr" // Type de l'enregistrement
  #define szfCYCLES_CYCLE   "Cycle"   // Cycle

  #define FmtPREFILTRE szfCYCLES_RACINE ">='%c' AND " szfCYCLES_RACINE "<'%c' AND " szfCYCLES_TYPEENR " ="

  int nLenCompte,                                //Longueur du compte dont on veut retrouver le cycle
      nLenRacine,                                //Longueur d'une racine de compte
      eTypeEnr;                                  //Type de l'enregistrement en cours de recherche dans la table des cycles
  TField *pfldRacine;                            //Le champ "Racine" de la table des cycles
  TIntegerField *ptblCycle;
  enum CODE_CYCLE eCycle;                        //Valeur de retour de la fonction
  unsigned char cClasseCompte;                   //Classe du compte
  char szPreFiltre[sizeof(FmtPREFILTRE)];        //Pré-Filtre sur la table des cycles
  AnsiString strRacine;                          //Une racine de compte (de la table "Cycles")

  ASSERT(ptblCycles);
  ASSERT(ptblCycles->Active);

    //////////////////////////////////////////////
    // Recherche des caractéristiques du compte //
    //////////////////////////////////////////////
    // Initialisation des caractéristiques du compte
    eCycle = CYC_AUTRES_CPTS;           // Par défaut, un compte va dans le cycle "Autres comptes"
    bIntoCycleFinal = false;            // ...et n'est donc pas dans le cycle final
    // Initialisations pour la recherche
    pfldRacine = ptblCycles->FieldByName(szfCYCLES_RACINE);
    ptblCycle = (TIntegerField *)ptblCycles->FieldByName(szfCYCLES_CYCLE);
    nLenCompte = strCompte.Length();
    // Préparation du filtre de restriction pour la recherche
    // (ce filtre n'attend plus que le type d'enregistrement - i.e. la caractéristique - sur lequel effectuer la recherche)
    cClasseCompte = *strCompte.c_str();
    sprintf(szPreFiltre,FmtPREFILTRE,(char)cClasseCompte,(char)(cClasseCompte + 1));

    ASSERT_VALID_STRING(szPreFiltre);

    ptblCycles->Filtered = true;
    ptblCycles->SetKey();                        // Préparation de la racine à partir de laquelle commencer la recherche
    pfldRacine->Value = strCompte;
    // Recherches
    for (eTypeEnr = RACINESTYPEENR_FIRST;eTypeEnr <= RACINESTYPEENR_LAST;eTypeEnr++)
    {
      ptblCycles->Filter = szPreFiltre + AnsiString(eTypeEnr);       // MAJ du filtrage (pour n'obtenir que la classe de comptes concernée ET le type d'enreg souhaité)
      ptblCycles->GotoNearest();                 // Positionnement sur "Racine >= strCompte"
      // Recherche
      while(!ptblCycles->Bof)
      {
        strRacine = pfldRacine->AsString;
        if((nLenRacine = strRacine.Length()) <= nLenCompte)          // Cette racine contient peut-être le compte
          if(strRacine == strCompte.SubString(1,nLenRacine))
          { // Cette racine contient le compte => Lecture de la caractéristique du compte
            switch (eTypeEnr)
            {
              case RACINESTYPEENR_RACINE_CYCLE_STANDARD:   // => Lecture du cycle standard du compte
                eCycle = (enum CODE_CYCLE)ptblCycle->AsInteger;
                break;
              case RACINESTYPEENR_RACINE_CYCLE_FINAL:      // => Ce compte appartient au cycle final
                bIntoCycleFinal = true; // La présence de cet enregistrement IMPLIQUE l'appartenance du compte au cycle final
                break;
              default : ASSERT(false);
            }
            // Fin de la lecture des caractéristiques du compte et de la recherche
            break;
          }
        // On continue la recherche sur la racine précédente (l'ordre est ASCII)
        ptblCycles->Prior();
      }
    }
  return eCycle;
  #undef FmtPREFILTRE
 } /* TTablePC::GetPropsUnCompte() */

 enum CODE_CYCLE __fastcall TTablePC::GetPropsUnCompte(MapRacineCycle *mapRacineCycle,
                                                        const AnsiString& strCompte,
                                                        bool&             bIntoCycleFinal)
 {
  enum RACINESTypeEnr {
    RACINESTYPEENR_RACINE_CYCLE_STANDARD = 0, // Donne le cycle standard des comptes de cette classe
    RACINESTYPEENR_RACINE_CYCLE_FINAL    = 1, // Les comptes de cette racine sont à viser aussi dans le cycle final

    RACINESTYPEENR_FIRST = RACINESTYPEENR_RACINE_CYCLE_STANDARD,
    RACINESTYPEENR_LAST  = RACINESTYPEENR_RACINE_CYCLE_FINAL
  };
  int nLenCompte,                                //Longueur du compte dont on veut retrouver le cycle
      eTypeEnr;                                  //Type de l'enregistrement en cours de recherche dans la table des cycles
  enum CODE_CYCLE eCycle;                        //Valeur de retour de la fonction
  AnsiString strRacine;                          
  MapRacineCycle::iterator it;
  cRacineTypeEnr RacineTypeEnr;
    //////////////////////////////////////////////
    // Recherche des caractéristiques du compte //
    //////////////////////////////////////////////
    // Initialisation des caractéristiques du compte
    eCycle = CYC_AUTRES_CPTS;           // Par défaut, un compte va dans le cycle "Autres comptes"
    bIntoCycleFinal = false;            // ...et n'est donc pas dans le cycle final
    // Initialisations pour la recherche
    nLenCompte = strCompte.Length();
    for (eTypeEnr = RACINESTYPEENR_FIRST;eTypeEnr <= RACINESTYPEENR_LAST;eTypeEnr++)
    {
      strRacine = strCompte;
      // Recherches
      for (int i=nLenCompte;i>0;i--)
      {
        RacineTypeEnr.strRacine = strRacine;
        RacineTypeEnr.TypeEnr = eTypeEnr;
        it = mapRacineCycle->find(RacineTypeEnr);
        if (it != mapRacineCycle->end())
        {
          switch (eTypeEnr)
          {
            case RACINESTYPEENR_RACINE_CYCLE_STANDARD:   // => Lecture du cycle standard du compte
              eCycle = it->second;
              break;
            case RACINESTYPEENR_RACINE_CYCLE_FINAL:      // => Ce compte appartient au cycle final
              bIntoCycleFinal = true; // La présence de cet enregistrement IMPLIQUE l'appartenance du compte au cycle final
              break;
            default : ASSERT(false);
          }
          break;
        }
        strRacine.Delete(i,1);
      }
    }
  return eCycle;
 } /* TTablePC::GetPropsUnCompte() */

 /*----------------------------------------------------------------------------*\
 ------------- TTablePC::GetPropsCompte() ---------------------------------------
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette fonction permet de récupérer les propriétés d'un compte i.e.        -
 - d'indiquer à quel cycle un compte appartient, si ce compte doit figurer dans -
 - le cycle final et s'il est lettrable par défaut.                             -
 -                                                                              -
 - Paramètres :                                                                 -
 -   strCompte       : Compte dont on veut connaître le cycle.                  -
 -   bIntoCycleFinal : Retourne TRUE si le compte doit aussi figurer dans le CF -
 -   bRANDetailleDef : Retourne TRUE si le compte doit, par défaut, être repris -
 -                     en détail lors du Report A Nouveau.                      -
 -                                                                              -
 - Retour :                                                                     -
 -   Le code du cycle auquel le compte appartient (une valeur CYC_*).           -
 \*----------------------------------------------------------------------------*/
 /*enum CODE_CYCLE __fastcall TTablePC::GetPropsCompte(const AnsiString& strCompte,
                                                      bool&             bIntoCycleFinal)
 {
  CTable*         ptblCycles; // Table de définition des cycles et valeurs par défaut des comptes
  enum CODE_CYCLE eCycle;     // Code du cycle associé au compte
  ptblCycles = NULL;
  try {
    OuvrirTableCycles(ptblCycles);
    eCycle = GetPropsUnCompte(ptblCycles, strCompte, bIntoCycleFinal);
    FermerTableCycles(ptblCycles);
  } catch(Exception& e) {
    FermerTableCycles(ptblCycles);
    throw EUser(TAG(120), e);
  }
  return(eCycle);
 }    */

 enum CODE_CYCLE __fastcall TTablePC::GetPropsCompte(const AnsiString& strCompte,
                                                      bool&             bIntoCycleFinal)
 {
  CTable*         ptblCycles; // Table de définition des cycles et valeurs par défaut des comptes
  enum CODE_CYCLE eCycle;     // Code du cycle associé au compte
  ptblCycles = NULL;
  MapRacineCycle mapRacineCycle;
  try {
    OuvrirTableCycles(ptblCycles);
    CreerMapRacineCycle(ptblCycles,&mapRacineCycle);
    FermerTableCycles(ptblCycles);
    eCycle = GetPropsUnCompte(&mapRacineCycle, strCompte, bIntoCycleFinal);
  } catch(Exception& e) {
    FermerTableCycles(ptblCycles);
    throw EUser(TAG(120), e);
  }
  return(eCycle);
 }


void __fastcall TTablePC::RecalculerCycles(CBarre *Barre,bool ModifierANDetailles)
{
  CTable *ptblCycles;   // Table de définition des cycles et valeurs par défaut des comptes
  bool bRANDetaille; // TRUE si un compte doit être repris en détail lors du Report A Nouveau
  bool bCycleFinal;  // TRUE "  "    "    est dans le cycle final
  AnsiString Compte;

  ASSERT(Active);
  ASSERT(!Filtered);
  ASSERT(!OnFilterRecord);

  ptblCycles = NULL;
  MapRacineCycle mapRacineCycle;
  try
    {
      TStringField *pfCompte((TStringField*)FieldByName(strfPC_Compte));
      TIntegerField *pfCycle((TIntegerField*)FieldByName(strfPC_Cycle));
      TIntegerField *pfFlags((TIntegerField*)FieldByName(strfPC_Flags));
      TIntegerField *pfVisa((TIntegerField*)FieldByName(strfPC_Visa));
      TBooleanField *pfRANDetaille((TBooleanField*)FieldByName(strfPC_Lettrable));
      TIntegerField *pfTypeEnr((TIntegerField*)FieldByName(strfPC_TypeEnr));
      OuvrirTableCycles(ptblCycles);
      First();
      if (Barre)
        {
          Barre->MessageInfo = "Recalcul des cycles";
          (*Barre) = 0;
          Barre->Max = RecordCount;
        }
      CreerMapRacineCycle(ptblCycles,&mapRacineCycle);
      while(!Eof)
        {
          Compte = pfCompte->AsString;
          Edit();
          pfCycle->AsInteger = GetPropsUnCompte(/*ptblCycles*/&mapRacineCycle, Compte, bCycleFinal);
          if (bCycleFinal)
            pfFlags->AsInteger = pfFlags->AsInteger | PCFLAGS_COMPTE_CYCLE_FINAL;
          else
          {
            pfFlags->AsInteger = pfFlags->AsInteger & ~PCFLAGS_COMPTE_CYCLE_FINAL;
            if (pfTypeEnr->AsInteger != PCTYPEENR_PROGRAMME_DE_TRAVAIL)
              pfVisa->AsInteger = pfVisa->AsInteger & ~PCVISA_FINAL_PAR_FINAL;  //On enlève le visa du cycle final si le compte n'est pas visable dans le cycle final
          }
          if (ModifierANDetailles)
            pfRANDetaille->AsBoolean = bRANDetaille;
          Next();
          if (Barre)
            (*Barre)++;
        }
      FermerTableCycles(ptblCycles);
    }
  catch(Exception &e)
    {
      Cancel();
      FermerTableCycles(ptblCycles);
      throw EUser(TAG(130), e.Message + "\n"
                       "Compte : " + Compte);
    }
}



void __fastcall TTablePC::RecalculerCycle(const AnsiString &Compte,int &Cycle,bool &CycleFinal)
{
  CTable *ptblCycles;   // Table de définition des cycles et valeurs par défaut des comptes
  bool bCycleFinal;  // TRUE "  "    "    est dans le cycle final
  ptblCycles = 0;
  MapRacineCycle mapRacineCycle;
  try
    {
      OuvrirTableCycles(ptblCycles);
      CreerMapRacineCycle(ptblCycles,&mapRacineCycle);
      Cycle = GetPropsUnCompte(/*ptblCycles*/&mapRacineCycle,Compte,bCycleFinal);
      CycleFinal = bCycleFinal ? PCFLAGS_COMPTE_CYCLE_FINAL : PCFLAGS_AUCUN;
      FermerTableCycles(ptblCycles);
    }
  catch(Exception &e)
    {
      FermerTableCycles(ptblCycles);
      throw EUser(TAG(130), e);
    }
}


void __fastcall TTablePC::CreerMapRacineCycle(CTable *ptblCycles,MapRacineCycle *mapRacineCycle)
{
  TStringField *pfldRacine;
  TIntegerField *pfldCycle;
  TIntegerField *pfldTypeEnr;
  cRacineTypeEnr RacineTypeEnr;
  #define szfCYCLES_RACINE  "Racine"  // Racine
  #define szfCYCLES_TYPEENR "TypeEnr" // Type de l'enregistrement
  #define szfCYCLES_CYCLE   "Cycle"   // Cycle
  try
    {
      mapRacineCycle->clear();
      pfldRacine = (TStringField*)ptblCycles->FieldByName(szfCYCLES_RACINE);
      pfldCycle = (TIntegerField *)ptblCycles->FieldByName(szfCYCLES_CYCLE);
      pfldTypeEnr = (TIntegerField *)ptblCycles->FieldByName(szfCYCLES_TYPEENR);
      SCAN_TABLE(ptblCycles)
      {
        RacineTypeEnr.TypeEnr = pfldTypeEnr->AsInteger;
        RacineTypeEnr.strRacine = pfldRacine->AsString;
        mapRacineCycle->insert(MapRacineCycle::value_type(RacineTypeEnr,(CODE_CYCLE)pfldCycle->AsInteger));
      }
    }
  catch(Exception &e)
    {
      throw EUser(TAG(1510), e);
    }
}

bool __fastcall TTablePC::AllerSurLeCompteCollectifDe(const AnsiString &Compte)
{
  TStringField *tblPCCompte;
  AnsiString CompteAChercher;
  tblPCCompte = (TStringField *)FieldByName(strfPC_Compte);

  ASSERT(IndexName.IsEmpty());
  ASSERT(!Filtered);

  CompteAChercher = Compte;
  while (!CompteAChercher.IsEmpty())
    {
      SetKey();
      KeyFieldCount = 1;
      tblPCCompte->AsString = CompteAChercher;
      if (GotoKey())
        {//On a peut-être trouvé le compte collectif
          if (EstUnCompteCollectif)
            return true;                         //On a trouvé le compte collectif
          while (!Eof && (tblPCCompte->AsString == CompteAChercher)) //On va chercher après
            if (EstUnCompteCollectif)
              return true;                       //On a trouvé le compte collectif
            else
              Next();
        }
      CompteAChercher.Delete(CompteAChercher.Length(),1);  //On va chercher une autre sous-racine
    }
  return false;
}




bool __fastcall TTablePC::EstLeCollectifDe(const AnsiString &CompteAux,const AnsiString &CompteCollectif)
{
  return (CompteAux.Pos(CompteCollectif) == 1);
}



//-----------------------------------------//
// Fonction de lecture du champ 'Drapeaux' //
//-----------------------------------------//
bool __fastcall TTablePC::GetDrapeaux( int nIndex)
{
  return (( FieldByName( strfPC_Drapeaux)->AsInteger & nIndex) != 0);
}



//-----------------------------------------//
// Fonction d'écriture du champ 'Drapeaux" //
//-----------------------------------------//
void __fastcall TTablePC::SetDrapeaux( bool bValue, PCDrapeaux eIndex)
{
  if ( bValue) FieldByName( strfPC_Drapeaux)->AsInteger |=  ( DWORD)eIndex;
          else FieldByName( strfPC_Drapeaux)->AsInteger &= ~( DWORD)eIndex;
}


 //------------------------------------------------------------------------------
 //
 // Change le solde d'un compte
 //
void __fastcall TTablePC::ChangeSolde(const AnsiString &strCompte,
                                      const Currency &curMontant,
                                      bool bCredit,
                                      const TDateTime &DateOperation,
                                      bool Collectif)
{
  TCurrencyField *pfldDebitOuCredit,*tblPCDebit,*tblPCCredit,*tblPCDebitTotal,*tblPCCreditTotal,*tblPCDebitSituation,*tblPCCreditSituation;
  if (Collectif)
    {
      if (!AllerSurLeCompteCollectifDe(strCompte))
        EICErreur(AnsiString("Impossible de trouver le collectif du compte ") + strCompte);
    }
  else
    {
      if (!AllerSurLeCompte(strCompte))
        EICErreur(AnsiString("Impossible de trouver le compte ") + strCompte);
    }
  tblPCDebit = (TCurrencyField*)FieldByName(strfPC_Debit);
  tblPCCredit = (TCurrencyField*)FieldByName(strfPC_Credit);
  tblPCDebitTotal = (TCurrencyField*)FieldByName(strfPC_DebitTotal);
  tblPCCreditTotal = (TCurrencyField*)FieldByName(strfPC_CreditTotal);
  tblPCDebitSituation = (TCurrencyField*)FieldByName(strfPC_DebitSituation);
  tblPCCreditSituation = (TCurrencyField*)FieldByName(strfPC_CreditSituation);
  pfldDebitOuCredit = bCredit ? tblPCCreditTotal : tblPCDebitTotal;
  try
    {
      Edit();
      //MAJ du solde Total
      if (pfldDebitOuCredit->IsNull)
        pfldDebitOuCredit->AsCurrency = curMontant;
      else
        pfldDebitOuCredit->AsCurrency = pfldDebitOuCredit->AsCurrency + curMontant;
      //MAJ du solde Visible
      if (!cm_SoldeVisibleEgalSituation || (DateOperation <= cm_DateSituation))
        {
          pfldDebitOuCredit = bCredit ? tblPCCredit : tblPCDebit;
          if (pfldDebitOuCredit->IsNull)
            pfldDebitOuCredit->AsCurrency = curMontant;
          else
            pfldDebitOuCredit->AsCurrency = pfldDebitOuCredit->AsCurrency + curMontant;
        }
      //MAJ du solde de Situation
      if (DateOperation <= cm_DateSituation)
        {
          FieldByName(strfPC_Visa)->AsInteger = PCVISA_AUCUN;  // ....Fait sauter les visas
          pfldDebitOuCredit = bCredit ? tblPCCreditSituation : tblPCDebitSituation;
          if (pfldDebitOuCredit->IsNull)
            pfldDebitOuCredit->AsCurrency = curMontant;
          else
            pfldDebitOuCredit->AsCurrency = pfldDebitOuCredit->AsCurrency + curMontant;
        }
      Post();
    }
  catch (Exception &e)
    {
      Cancel();
      throw EUser(TAGL,e);
    }
  if (!Collectif && (tblPCDebitTotal->AsCurrency == 0.0) && (tblPCCreditTotal->AsCurrency == 0.0))
    {//On vérifie que le compte comporte encore des écritures
      TTableHI *tblHI;
      try
        {
          tblHI = new TTableHI(0);
          tblHI->Filter = TTableHI::strfHI_Compte + "='" + strCompte + "' and " szfHI_EstCrediteur "='false'";
          tblHI->Filtered = true;
          tblHI->Open();
          if (tblHI->IsEmpty())
            {//Il n'y a pas d'écriture, on supprime le débit et le crédit
              try
                {
                  Edit();
                  tblPCDebit->Clear();
                  tblPCDebitTotal->Clear();
                  tblPCDebitSituation->Clear();
                  Post();
                }
              catch (Exception &e)
                {
                  Cancel();
                  throw EUser(TAGL,e);
                }
            }
          tblHI->Filter = TTableHI::strfHI_Compte + "='" + strCompte + "' and " szfHI_EstCrediteur "='true'";
          if (tblHI->IsEmpty())
            {//Il n'y a pas d'écriture, on supprime le débit et le crédit
              try
                {
                  Edit();
                  tblPCCredit->Clear();
                  tblPCCreditTotal->Clear();
                  tblPCCreditSituation->Clear();
                  Post();
                }
              catch (Exception &e)
                {
                  Cancel();
                  throw EUser(TAGL,e);
                }
            }
          tblHI->Close();
        }
      catch (Exception &e)
        {
          delete tblHI;
          throw EUser(TAGL,e); //TAG(1)
        }
      delete tblHI;
    }
  if (EstUnCompteAuxiliaire)
    ChangeSolde(strCompte,curMontant,bCredit,DateOperation,true);
}


 /******************************************************************************\
 ************* TTablePC::AllerSurLeProgrammeDeTravail() *************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de retourner un programme de travail du PC.         *
 *                                                                              *
 * Paramètres :                                                                 *
 *   strRacine : Racine à rechercher dans le PC                                 *
 *                                                                              *
 * Retour :                                                                     *
 *   TRUE si la racine a été trouvé dans le PC (auquel cas, l'enregistrement    *
 * courant est le programme de travail lui-même); FALSE sinon                   *
 \******************************************************************************/
bool __fastcall TTablePC::AllerSurLeProgrammeDeTravail(const AnsiString& strRacine)
{
  ASSERT(State == dsBrowse);

  try
    {
      if (Locate(strfPC_Compte,strRacine,_loNormal))
        do
          {
            if (FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_PROGRAMME_DE_TRAVAIL)
              {// La racine est bien dans le PC
                return(true);
              }
            Next();
          }
        while (!Eof && (FieldByName(strfPC_Compte)->AsString == strRacine));
    }
  catch(Exception& e)
    {
      return false;
    }
  return (false);
} /* TTablePC::AllerSurLeProgrammeDeTravail() */


 /******************************************************************************\
 ************* TTablePC::CreerProgrammeDeTravail() ******************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de créer un nouveau programme de travail            *
 *                                                                              *
 *                                                                              *
 * Paramètres :                                                                 *
 *   strCompte                : Racine du programme de travail                  *
 *   strDesignation           : Intitulé du programme de travail                *
 *                                                                              *
 * Retour :                                                                     *
 *   TRUE si le programme de travail a bien été créé; FALSE sinon (dans ce cas  *
 *   rien est fait)                                                             *
 *   On fait sauter le visa dans tous les cas.                                  *
 \******************************************************************************/
bool __fastcall TTablePC::CreerProgrammeDeTravail(const AnsiString& strRacine,
                                                  const AnsiString& strDesignation,
                                                  TTablePT * Table_PT)
{
  bool bCreated;                                 // TRUE si un programme a été effectivement créé
  bool bTmp;
  try
    {
      DisableControls();
      if(AllerSurLeProgrammeDeTravail(strRacine))
        { // Il existe déjà
          ASSERT(FieldByName(strfPC_Cycle)->AsInteger == GetPropsCompte(strRacine, bTmp)); // Le cycle du PT doit être correct
          Edit();
          FieldByName(strfPC_Intitule)->AsString = strDesignation.IsEmpty() ? AnsiString(_strPtInterro) : strDesignation;
          Post();
          bCreated = false;
        }
      else
        { // Il n'existe pas
          Insert();
          FieldByName(strfPC_Cycle)->AsInteger = GetPropsCompte(strRacine, bTmp);
          FieldByName(strfPC_Compte)->AsString = strRacine;
          FieldByName(strfPC_Intitule)->AsString = strDesignation.IsEmpty() ? AnsiString(_strPtInterro) : strDesignation;
          FieldByName(strfPC_TypeEnr)->AsInteger = PCTYPEENR_PROGRAMME_DE_TRAVAIL;
          Post();
          bCreated = true;
        }
      ViserProgrammeDeTravail(false,Table_PT);   //On enlève le visa dans le PC et le PT
      EnableControls();
    }
  catch(Exception& e)
    {
      Cancel();
      EnableControls();
      throw EUser(TAG(140),e);
    }
  return(bCreated);
} /* TTablePC::CreerProgrammeDeTravail() */


 /******************************************************************************\
 ************* TTablePC::ViserProgrammeDeTravail() ******************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de viser ou déviser le programme de travail courant.*
 *                                                                              *
 * Paramètres :                                                                 *
 *   bViser     : TRUE/FALSE s'il faut viser/déviser le PT courant.             *
 *   Table_PT   : table $$O où se trouvent les consignes à viser elles aussi    *
 *                (indiquer NULL pour ne pas viser les consignes du PT).        *
 \******************************************************************************/
 void __fastcall TTablePC::ViserProgrammeDeTravail(bool bViser,TTablePT * Table_PT)
 {
  EICTag tag;

  ASSERT((State == dsBrowse) || (State == dsFilter) || (State == dsEdit));
  ASSERT(FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_PROGRAMME_DE_TRAVAIL);


  try
    {
    /////////////////////////////////////////
    // On (Dé)vise les consignes associées //
    /////////////////////////////////////////
      if(Table_PT)
        {
          tag = TAG(150);
          Table_PT->ViserRacine(FieldByName(strfPC_Compte)->AsString,bViser);
        }


    ///////////////////////
    // On (dé)vise le PT //
    ///////////////////////
      tag = TAG(151);
      Edit();
      FieldByName(strfPC_Visa)->AsInteger = bViser ? PCVISA_PROGRAMME_DE_TRAVAIL : PCVISA_AUCUN;
      Post();
    }
  catch(Exception& e)
    {
      Cancel();
      throw EUser(tag,e);
    }
 } /* TTablePC::ViserProgrammeDeTravail() */


 /******************************************************************************\
 ************* TTablePC::FiltrerProgrammeDeTravail() ****************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de filtrer les programmes de travail courant.       *
 *                                                                              *
 \******************************************************************************/
void __fastcall TTablePC::FiltrerProgrammeDeTravail()
{
  Filter = szfPC_TypeEnr "=" + AnsiString((int)PCTYPEENR_PROGRAMME_DE_TRAVAIL);
  Filtered = true;
} /* TTablePC::FiltrerProgrammeDeTravail() */


 /******************************************************************************\
 ************* TTablePC::SupprimerProgrammeDeTravail() **************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de supprimer le programme de travail courant et     *
 *    toutes les consignes si rapportant.                                       *
 *                                                                              *
 * Paramètres :                                                                 *
 *   Table_PT   : table PT                                                      *
 *                                                                              *
 \******************************************************************************/
void __fastcall TTablePC::SupprimerProgrammeDeTravail(TTablePT * Table_PT)
{
  ASSERT(State == dsBrowse);
  ASSERT(!IsEmpty());
  ASSERT(FieldByName(strfPC_TypeEnr)->AsInteger == PCTYPEENR_PROGRAMME_DE_TRAVAIL);

  try
    {
      Table_PT->SupprimerConsignes(FieldByName(strfPC_Compte)->AsString);
      Delete();
    }
  catch(Exception& e)
    {
      Cancel();
      throw EUser(TAG(170),e);
    }
} /* TTablePC::SupprimerProgrammeDeTravail() */

void __fastcall TTablePC::ConvertirSoldesNm1Nm2TenueEuro( CBarre *pBarre)
{
  ASSERT(  Active);
  ASSERT( !Filtered);
  ASSERT( !MasterSource);

  TCurrencyField *pfldSoldeNm1  = ( TCurrencyField*)FieldByName( strfPC_SoldeNm1       );
  TCurrencyField *pfldSoldeNm2  = ( TCurrencyField*)FieldByName( strfPC_SoldeNm2       );
  TCurrencyField *pfldSoldeNm3  = ( TCurrencyField*)FieldByName( strfPC_SoldeNm3       );
  TCurrencyField *pfldSoldeNm4  = ( TCurrencyField*)FieldByName( strfPC_SoldeNm4       );

  try {
    if ( pBarre) (*pBarre).Max = RecordCount;
    First();
    while( !Eof) {
      if ( EstUnCompte) {
        Edit();
        if ( !pfldSoldeNm1->IsNull) pfldSoldeNm1->AsCurrency = ConvertFrancToEuro(pfldSoldeNm1->AsCurrency);
        if ( !pfldSoldeNm2->IsNull) pfldSoldeNm2->AsCurrency = ConvertFrancToEuro(pfldSoldeNm2->AsCurrency);
        if ( !pfldSoldeNm3->IsNull) pfldSoldeNm3->AsCurrency = ConvertFrancToEuro(pfldSoldeNm3->AsCurrency);
        if ( !pfldSoldeNm4->IsNull) pfldSoldeNm4->AsCurrency = ConvertFrancToEuro(pfldSoldeNm4->AsCurrency);
      }
      Next();
      if ( pBarre) (*pBarre)++;
    }

    EquilibrerNm1Nm2Tenue();
    CalculerSoldesCollectifs();
  } catch( Exception &e) {
    throw EUser( TAG( 180), e);
  }
}

bool __fastcall TTablePC::EquilibrerNm1Nm2Tenue()
{
  ASSERT(  Active);
  ASSERT( !Filtered);
  ASSERT( !MasterSource);

  Currency curSoldeNm1,curSoldeNm2,curSoldeNm3,curSoldeNm4;
  TCurrencyField *pfldSoldeNm1Tenue = ( TCurrencyField*)FieldByName( strfPC_SoldeNm1);
  TCurrencyField *pfldSoldeNm2Tenue = ( TCurrencyField*)FieldByName( strfPC_SoldeNm2);
  TCurrencyField *pfldSoldeNm3Tenue = ( TCurrencyField*)FieldByName( strfPC_SoldeNm3);
  TCurrencyField *pfldSoldeNm4Tenue = ( TCurrencyField*)FieldByName( strfPC_SoldeNm4);
  bool            bModifier         = false;
  // Création des comptes d'arrondis ( profit / change )
  CreerComptesArrondis();
  // Calcule les soldes N-1 et N-2
  First();
  while( !Eof) {
    if ( EstUnCompte) {
      curSoldeNm1 = curSoldeNm1 + pfldSoldeNm1Tenue->AsCurrency;
      curSoldeNm2 = curSoldeNm2 + pfldSoldeNm2Tenue->AsCurrency;
      curSoldeNm3 = curSoldeNm3 + pfldSoldeNm3Tenue->AsCurrency;
      curSoldeNm4 = curSoldeNm4 + pfldSoldeNm4Tenue->AsCurrency;
    }
    Next();
  }
  // Ajustement des soldes N-1 à N-4
  if ( curSoldeNm1!=0) {
    AllerSurLeCompte( curSoldeNm1>0 ? cm_strCptProfiArrondis : cm_strCptPerteArrondis);
    Edit();
    pfldSoldeNm1Tenue->AsCurrency = pfldSoldeNm1Tenue->AsCurrency - curSoldeNm1;
    Post();
    bModifier = true;
  }
  if ( curSoldeNm2!=0) {
    AllerSurLeCompte( curSoldeNm2>0 ? cm_strCptProfiArrondis : cm_strCptPerteArrondis);
    Edit();
    pfldSoldeNm2Tenue->AsCurrency = pfldSoldeNm2Tenue->AsCurrency - curSoldeNm2;
    Post();
    bModifier = true;
  }
  if ( curSoldeNm3!=0) {
    AllerSurLeCompte( curSoldeNm3>0 ? cm_strCptProfiArrondis : cm_strCptPerteArrondis);
    Edit();
    pfldSoldeNm3Tenue->AsCurrency = pfldSoldeNm3Tenue->AsCurrency - curSoldeNm3;
    Post();
    bModifier = true;
  }
  if ( curSoldeNm4!=0) {
    AllerSurLeCompte( curSoldeNm4>0 ? cm_strCptProfiArrondis : cm_strCptPerteArrondis);
    Edit();
    pfldSoldeNm4Tenue->AsCurrency = pfldSoldeNm4Tenue->AsCurrency - curSoldeNm4;
    Post();
    bModifier = true;
  }

  return bModifier;
}


 //**********//
 // TTableHI //
 //**********////////////////////////////////////////////////////////////////////
 //                                                                            //
 //    Cette classe implémente les fonctions et opérations nécessaires à la    //
 // gestion d'un historique.                                                   //
 ////////////////////////////////////////////////////////////////////////////////
 /*----------------------------------------------------------------------------*\
 ------------- TTableHI::GetAutoID() --------------------------------------------
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette fonction (de lecture de la propriété AutoID) donne l'ID auto        -
 - incrémenté de la ligne courante.                                             -
 -                                                                              -
 - Retour :                                                                     -
 -   L'ID - unique sur toute la vie de la table - de la ligne courante.         -
 \*----------------------------------------------------------------------------*/
 int __fastcall TTableHI::GetAutoID()
 {
  ASSERT((State == dsBrowse) || (State == dsCalcFields));
  ASSERT(!FieldByName(strfHI_AutoID)->IsNull);

  return(FieldByName(strfHI_AutoID)->AsInteger);
 } /* TTableHI::GetAutoID() */


 /*----------------------------------------------------------------------------*\
 ------------- TTableHI::GetEstCrediteur() --------------------------------------
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette fonction (de lecture de la propriété EstCrediteur) permet de savoir -
 - si le montant courant est créditeur ou non.                                  -
 -                                                                              -
 - Retour :                                                                     -
 -   TRUE si le montant courant est créditeur; FALSE sinon.                     -
 \*----------------------------------------------------------------------------*/
 bool __fastcall TTableHI::GetEstCrediteur()
 {
  ASSERT(!FieldByName(strfHI_EstCrediteur)->IsNull);

  return(FieldByName(strfHI_EstCrediteur)->AsBoolean);
 } /* TTableHI::GetEstCrediteur() */


 /*----------------------------------------------------------------------------*\
 ------------- TTableHI::SetEstCrediteur() --------------------------------------
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette fonction (d'écriture de la propriété EstCrediteur) permet d'indiquer-
 - que le montant courant doit être créditeur sinon débiteur.                   -
 -                                                                              -
 - Paramètres :                                                                 -
 -   bEstCrediteur : TRUE si le montant courant doit être créditeur; FALS sinon.-
 \*----------------------------------------------------------------------------*/
 void __fastcall TTableHI::SetEstCrediteur(bool bEstCrediteur)
 {
  FieldByName(strfHI_EstCrediteur)->AsBoolean = bEstCrediteur;
 } /* TTableHI::SetEstCrediteur() */


 /*----------------------------------------------------------------------------*\
 ------------- TTableHI::GetEstUneLigneAnnulee() --------------------------------
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette fonction (de lecture de la propriété EstUneLigneAnnulee) permet de  -
 - savoir si la ligne courante est annulée ou non.                              -
 -                                                                              -
 - Retour :                                                                     -
 -   TRUE si la ligne courante est annulée; FALSE sinon.                        -
 \*----------------------------------------------------------------------------*/
 bool __fastcall TTableHI::GetEstUneLigneAnnulee()
 {
  TIntegerField* pfldFlags; // Champs "Drapeaux de la ligne"

  ASSERT((State == dsBrowse) || (State == dsFilter));
  ASSERT(!FieldByName(strfHI_Flags)->IsNull);

  pfldFlags = (TIntegerField*)FieldByName(strfHI_Flags);
  return(pfldFlags->AsInteger & HIFLAGS_EST_ANNULEE);
 } /* TTableHI::GetEstUneLigneAnnulee() */


 /******************************************************************************\
 ************* TTableHI::EstJnlMouvemente() *************************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de savoir si un journal est mouvementé ou non.      *
 *                                                                              *
 * Paramètres :                                                                 *
 *   strCodeJnl : Code du journal pour lequel on désire savoir si au moins une  *
 *                écriture a été passée dans l'exercice (i.e. est mouvementé).  *
 *                                                                              *
 * Retour :                                                                     *
 *   TRUE si le journal est mouvementé sur N; FALSE sinon.                      *
 \******************************************************************************/
 bool __fastcall TTableHI::EstJnlMouvemente(const AnsiString& strCodeJnl)
 {
  ASSERT(!Filtered);


  //////////////////////////////////////////////
  // Recherche d'une écriture dans le journal //
  //////////////////////////////////////////////
  if(Locate(strfHI_CodeJournal, strCodeJnl, _loInsensitive))
  { // Une écriture au moins existe dans ce journal
    return(true);
  }
  else
  { // Aucune écriture ne mouvemente ce journal
    return(false);
  }
 } /* TTableHI::EstJnlMouvemente() */


 /******************************************************************************\
 ************* TTableHI::Cloturer() *********************************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de clôturer l'historique (Ouvert, non filtré/trié et*
 * pour un accès en lecture seulement) dans un nouvel Histo et le PC lié à cet  *
 * historique (en fait, le PC lié est une copie du PC d'origine).               *
 *                                                                              *
 * Paramètres :                                                                 *
 *   dateFinExN     : Date de fin de l'exercice N (celui à clôturer).           *
 *   strJnlANouveau : Code du journal d'"A Nouveaux".                           *
 *   ptblHINp1      : Histo N+1 résultant de la clôture (Ouvert, Exclusif, Vide,*
 *                    non filtré, et mêmes champs que ptblHIN).                 *
 *   ptblPC         : PC lié au HI à clôturer (Ouvert et non filtré/trié).      *
 *   pBarre         : Barre de progression (Ouverte).                           *
 *                                                                              *
 * Note : Si une erreur survient pendant la clôture, une exception est levée.   *
 \******************************************************************************/
 void __fastcall TTableHI::Cloturer(const TDateTime &dateFinExN,
                                    const TDateTime &dateFinExNp1,
                                    const AnsiString &strJnlANouveau,
                                    const AnsiString &CompteResultatPerte,
                                    const AnsiString &CompteResultatBenefice,
                                    TTableHI *ptblHINp1,
                                    TTablePC *ptblPC,
                                    TTable *tblNotes,
                                    TTableHI *tblINVR,
                                    CTable   *ptblHI2,
                                    CTable   *ptblHI2Np1,
                                    bool ANEnDetail,
                                    CBarre *pBarre)
 {
  #define _strIntiuleANouveau "A Nouveau"

  TDateTime dateDebExNp1((int)dateFinExN + 1); // Date de début de l'exercice N+1
  Currency  curResultat;                       // Résultat de l'exercice (calculé via les comptes 1 à 5)
  Currency  curPCSolde;                        // Un solde du PC
  FilterID  fid;                               // Un ID de filtre
  bool      bDossierFRF;                       // TRUE si la devise du dossier est FRF
  EICTag    Tag;

  TDateTimeField* pfldDateImputation; // Champs de cet histo (à lire seulement)
  TDateTimeField* pfldDateEcheance;
  TDateTimeField* pfldDateEP;
  TDateTimeField* pfldDateExport;
  TStringField*   pfldCompte;
  TStringField*   pfldCodeJournal;
  TDateTimeField* pfldRANDateO;
  TStringField*   pfldRANJournalO;
  TStringField*   pfldPiece;
  TStringField*   pfldPieceExterne;
  TStringField*   pfldNatPiece;
  TStringField*   pfldLettrage;
  TIntegerField*  pfldFlagLettrage;
  TIntegerField*  pfldIDEcriture;
  TIntegerField*  pfldIDEcriturePart;
  TStringField*   pfldLibelleOperation;
  TCurrencyField* pfldMontantO;
  TIntegerField*  pfldCodeDevise;
  TFloatField*    pfldTauxChange;
  TCurrencyField* pfldMontant;
  TBooleanField*  pfldCrediteur;
  TStringField*   pfldRAOData;
  TDateTimeField* pfldDateDebPeriode;
  TDateTimeField* pfldDateFinPeriode;
  TIntegerField*  pfldRAOIDEcriture;
  TIntegerField*  pfldFlags;
  TFloatField*    pfldQuantite;
  TIntegerField*  pfldModePaiement;
  TStringField*   pfldBanque;
  TStringField*   pfldCodeAnalytique;
  TStringField*   pfldIDImage;
  TIntegerField*  pfldReviseur;
  TIntegerField*  pfldReference;
  TStringField*   pfldCodeTVA;
  TFloatField*    pfldTauxTVA;
  TStringField*   pfldDesignation;

  TStringField*   pfldPCCompte;    // Champs du PC
  TBooleanField*  pfldPCRANDetaille;
  TIntegerField*  pfldPCVisas;
  TCurrencyField* pfldPCDebit;
  TCurrencyField* pfldPCCredit;
  TCurrencyField* pfldPCDebitSituation;
  TCurrencyField* pfldPCCreditSituation;
  TCurrencyField* pfldPCDebitTotal;
  TCurrencyField* pfldPCCreditTotal;
  TCurrencyField* pfldPCSoldeNm1;
  TCurrencyField* pfldPCSoldeNm2;
  TCurrencyField* pfldPCSoldeNm3;
  TCurrencyField* pfldPCSoldeNm4;

  TDateTimeField* pfldHINp1DateImputation; // Champs de l'histo N+1
  TDateTimeField* pfldHINp1DateEcheance;
  TDateTimeField* pfldHINp1DateEP;
  TDateTimeField* pfldHINp1DateExport;
  TStringField*   pfldHINp1Compte;
  TStringField*   pfldHINp1CodeJournal;
  TDateTimeField* pfldHINp1RANDateO;
  TStringField*   pfldHINp1RANJournalO;
  TStringField*   pfldHINp1Piece;
  TStringField*   pfldHINp1PieceExterne;
  TStringField*   pfldHINp1NatPiece;
  TIntegerField*  pfldHINp1IDEcriture;
  TIntegerField*  pfldHINp1IDEcriturePart;
  TStringField*   pfldHINp1LibelleOperation;
  TCurrencyField* pfldHINp1MontantO;
  TIntegerField*  pfldHINp1CodeDevise;
  TFloatField*    pfldHINp1TauxChange;
  TCurrencyField* pfldHINp1Montant;
  TBooleanField*  pfldHINp1Crediteur;
  TStringField*   pfldHINp1Lettrage;
  TIntegerField*  pfldHINp1FlagLettrage;
  TStringField*   pfldHINp1RAOData;
  TDateTimeField* pfldHINp1DateDebPeriode;
  TDateTimeField* pfldHINp1DateFinPeriode;
  TIntegerField*  pfldHINp1RAOIDLigne;
  TIntegerField*  pfldHINp1Flags;
  TFloatField*    pfldHINp1Quantite;
  TIntegerField*  pfldHINp1ModePaiement;
  TStringField*   pfldHINp1Banque;
  TStringField*   pfldHINp1CodeAnalytique;
  TStringField*   pfldHINp1IDImage;
  TIntegerField*  pfldHINp1Reviseur;
  TIntegerField*  pfldHINp1Reference;
  TStringField*   pfldHINp1CodeTVA;
  TFloatField*    pfldHINp1TauxTVA;
  TStringField*   pfldHINp1Designation;
  TIntegerField*  pfldHINp1AutoID;
  TIntegerField*  pfldHI2Np1AutoID;


  TBooleanField *tblNotesReportNp1;
  ASSERT((DeviseCodeDefaut == DeviseCodeEuro) || (DeviseCodeDefaut == DeviseCodeFranc));
  ASSERT(Active);
  ASSERT(Exclusive);
  ASSERT(!Filtered);
  ASSERT(!OnFilterRecord);
  ASSERT(IndexName == EmptyStr);
  ASSERT((int)dateFinExN != 0);
  ASSERT(dateFinExN == TDateTime((int)dateFinExN));
  ASSERT(strJnlANouveau.Length() <= 4);
  ASSERT(ptblHINp1);
  ASSERT(ptblHINp1->Active);
  ASSERT(ptblHINp1->IsEmpty());
  ASSERT(!ptblHINp1->Filtered);
  ASSERT(!ptblHINp1->OnFilterRecord);
  ASSERT(ptblHI2Np1);
  ASSERT(ptblHI2Np1->Active);
  ASSERT(ptblHI2Np1->IsEmpty());
  ASSERT(!ptblHI2Np1->Filtered);
  ASSERT(!ptblHI2Np1->OnFilterRecord);
  ASSERT(ptblHI2);
  ASSERT(ptblHI2->Active);
  ASSERT(!ptblHI2->Filtered);
  ASSERT(!ptblHI2->OnFilterRecord);
  ASSERT(ptblPC);
  ASSERT(ptblPC->Active);
  ASSERT(!ptblPC->Filtered);
  ASSERT(!ptblPC->OnFilterRecord);
  ASSERT(ptblPC->IndexName.IsEmpty());
  ASSERT(pBarre);
  ASSERT(!tblINVR->Active);

  bDossierFRF = (DeviseCodeDefaut == DeviseCodeFranc);
  fid         = FID_NUL;


  try {
    Tag = TAG(190);
    pfldDateImputation  = (TDateTimeField*)FieldByName(strfHI_DateImputation);
    pfldDateEcheance    = (TDateTimeField*)FieldByName(strfHI_DateEcheance);
    pfldDateEP    = (TDateTimeField*)FieldByName(strfHI_DateEP);
    pfldDateExport      = (TDateTimeField*)FieldByName(strfHI_DateExport);
    pfldCompte          = (TStringField*)  FieldByName(strfHI_Compte);
    pfldCodeJournal     = (TStringField*)  FieldByName(strfHI_CodeJournal);
    pfldRANDateO        = (TDateTimeField*)ptblHI2->FieldByName(strfHI_RANDateOrigine);
    pfldRANJournalO         = (TStringField*)  ptblHI2->FieldByName(strfHI_RANJnlOrigine);
    pfldPiece           = (TStringField*)  FieldByName(strfHI_Piece);
    pfldPieceExterne    = (TStringField*)  ptblHI2->FieldByName(strfHI_PieceExterne);
    pfldNatPiece        = (TStringField*)  ptblHI2->FieldByName(strfHI_NaturePiece);
    pfldLettrage        = (TStringField*)  FieldByName(strfHI_Lettrage);
    pfldFlagLettrage    = (TIntegerField*) FieldByName(strfHI_FlagLettrage);
    pfldIDEcriture      = (TIntegerField*) FieldByName(strfHI_IDEcriture);
    pfldIDEcriturePart  = (TIntegerField*) ptblHI2->FieldByName(strfHI_IDEcriturePart);
    pfldLibelleOperation       = (TStringField*)  FieldByName(strfHI_LibelleOperation);
    pfldMontantO        = (TCurrencyField*)FieldByName(strfHI_MontantOrigine);
    pfldCodeDevise      = (TIntegerField*) FieldByName(strfHI_CodeDevise);
    pfldTauxChange      = (TFloatField*)   FieldByName(strfHI_TauxChange);
    pfldMontant         = (TCurrencyField*)FieldByName(strfHI_Montant);
    pfldCrediteur       = (TBooleanField*) FieldByName(strfHI_EstCrediteur);
    pfldRAOData         = (TStringField*)  ptblHI2->FieldByName(strfHI_RAOData);
    pfldDateDebPeriode  = (TDateTimeField*)ptblHI2->FindField(strfHI_DateDebPeriode);
    pfldDateFinPeriode  = (TDateTimeField*)ptblHI2->FindField(strfHI_DateFinPeriode);
    pfldRAOIDEcriture   = (TIntegerField*) ptblHI2->FieldByName(strfHI_RAOIDLigne);
    pfldFlags           = (TIntegerField*) FieldByName(strfHI_Flags);
    pfldQuantite        = (TFloatField*) ptblHI2->FieldByName(strfHI_Quantite);
    pfldModePaiement    = (TIntegerField*) FieldByName(strfHI_ModePaiement);
    pfldBanque          = (TStringField*)  ptblHI2->FieldByName(strfHI_Banque);
    pfldCodeAnalytique  = (TStringField*)  ptblHI2->FieldByName(strfHI_CodeAnalytik);
    pfldIDImage         = (TStringField*)  FieldByName(strfHI_IDImage);
    pfldReviseur        = (TIntegerField*) FieldByName(strfHI_Reviseur);
    pfldReference       = (TIntegerField*) FieldByName(strfHI_Reference);
    pfldCodeTVA         = (TStringField*) ptblHI2->FieldByName(strfHI_CodeTVA);
    pfldTauxTVA         = (TFloatField*) ptblHI2->FieldByName(strfHI_TauxTVA);
    pfldDesignation     = (TStringField*) ptblHI2->FieldByName(strfHI_Designation);


    Tag = TAG(191);
    pfldPCCompte        = (TStringField*)  ptblPC->FieldByName(TTablePC::strfPC_Compte);
    pfldPCRANDetaille   = (TBooleanField*) ptblPC->FieldByName(TTablePC::strfPC_Lettrable);
    pfldPCVisas         = (TIntegerField*) ptblPC->FieldByName(TTablePC::strfPC_Visa);
    pfldPCDebit         = (TCurrencyField*)ptblPC->FieldByName(TTablePC::strfPC_Debit);
    pfldPCCredit        = (TCurrencyField*)ptblPC->FieldByName(TTablePC::strfPC_Credit);
    pfldPCDebitSituation = (TCurrencyField*)ptblPC->FieldByName(TTablePC::strfPC_DebitSituation);
    pfldPCCreditSituation = (TCurrencyField*)ptblPC->FieldByName(TTablePC::strfPC_CreditSituation);
    pfldPCDebitTotal = (TCurrencyField*)ptblPC->FieldByName(TTablePC::strfPC_DebitTotal);
    pfldPCCreditTotal = (TCurrencyField*)ptblPC->FieldByName(TTablePC::strfPC_CreditTotal);
    pfldPCSoldeNm1      = (TCurrencyField*)ptblPC->FieldByName(TTablePC::strfPC_SoldeNm1);
    pfldPCSoldeNm2      = (TCurrencyField*)ptblPC->FieldByName(TTablePC::strfPC_SoldeNm2);
    pfldPCSoldeNm3      = (TCurrencyField*)ptblPC->FieldByName(TTablePC::strfPC_SoldeNm3);
    pfldPCSoldeNm4      = (TCurrencyField*)ptblPC->FieldByName(TTablePC::strfPC_SoldeNm4);

    Tag = TAG(192);
    pfldHINp1DateImputation  = (TDateTimeField*)ptblHINp1->FieldByName(strfHI_DateImputation);
    pfldHINp1DateEcheance = (TDateTimeField*)ptblHINp1->FieldByName(strfHI_DateEcheance);
    pfldHINp1DateEP = (TDateTimeField*)ptblHINp1->FieldByName(strfHI_DateEP);
    pfldHINp1DateExport = (TDateTimeField*)ptblHINp1->FieldByName(strfHI_DateExport);
    pfldHINp1Compte     = (TStringField*)  ptblHINp1->FieldByName(strfHI_Compte);
    pfldHINp1CodeJournal    = (TStringField*)  ptblHINp1->FieldByName(strfHI_CodeJournal);
    pfldHINp1RANDateO   = (TDateTimeField*)ptblHI2Np1->FieldByName(strfHI_RANDateOrigine);
    pfldHINp1RANJournalO    = (TStringField*)  ptblHI2Np1->FieldByName(strfHI_RANJnlOrigine);
    pfldHINp1Piece      = (TStringField*)  ptblHINp1->FieldByName(strfHI_Piece);
    pfldHINp1PieceExterne = (TStringField*)  ptblHI2Np1->FieldByName(strfHI_PieceExterne);
    pfldHINp1NatPiece   = (TStringField*)  ptblHI2Np1->FieldByName(strfHI_NaturePiece);
    pfldHINp1IDEcriture = (TIntegerField*) ptblHINp1->FieldByName(strfHI_IDEcriture);
    pfldHINp1IDEcriturePart = (TIntegerField*) ptblHI2Np1->FieldByName(strfHI_IDEcriturePart);
    pfldHINp1LibelleOperation  = (TStringField*)  ptblHINp1->FieldByName(strfHI_LibelleOperation);
    pfldHINp1MontantO   = (TCurrencyField*)ptblHINp1->FieldByName(strfHI_MontantOrigine);
    pfldHINp1CodeDevise = (TIntegerField*) ptblHINp1->FieldByName(strfHI_CodeDevise);
    pfldHINp1TauxChange = (TFloatField*)   ptblHINp1->FieldByName(strfHI_TauxChange);
    pfldHINp1Montant    = (TCurrencyField*)ptblHINp1->FieldByName(strfHI_Montant);
    pfldHINp1Crediteur  = (TBooleanField*) ptblHINp1->FieldByName(strfHI_EstCrediteur);
    pfldHINp1Lettrage   = (TStringField*)ptblHINp1->FieldByName(strfHI_Lettrage);
    pfldHINp1FlagLettrage = (TIntegerField*) ptblHINp1->FieldByName(strfHI_FlagLettrage);
    pfldHINp1RAOData    = (TStringField*)  ptblHI2Np1->FieldByName(strfHI_RAOData);
    pfldHINp1DateDebPeriode = (TDateTimeField*)ptblHI2Np1->FindField(strfHI_DateDebPeriode);
    pfldHINp1DateFinPeriode = (TDateTimeField*)ptblHI2Np1->FindField(strfHI_DateFinPeriode);
    pfldHINp1RAOIDLigne   = (TIntegerField*) ptblHI2Np1->FieldByName(strfHI_RAOIDLigne);
    pfldHINp1Flags      = (TIntegerField*) ptblHINp1->FieldByName(strfHI_Flags);
    pfldHINp1Quantite   = (TFloatField*) ptblHI2Np1->FieldByName(strfHI_Quantite);
    pfldHINp1ModePaiement = (TIntegerField*) ptblHINp1->FieldByName(strfHI_ModePaiement);
    pfldHINp1Banque    = (TStringField*)  ptblHI2Np1->FieldByName(strfHI_Banque);
    pfldHINp1CodeAnalytique  = (TStringField*)  ptblHI2Np1->FieldByName(strfHI_CodeAnalytik);
    pfldHINp1IDImage    = (TStringField*)  ptblHINp1->FieldByName(strfHI_IDImage);
    pfldHINp1Reviseur   = (TIntegerField*) ptblHINp1->FieldByName(strfHI_Reviseur);
    pfldHINp1Reference  = (TIntegerField*) ptblHINp1->FieldByName(strfHI_Reference);
    pfldHINp1CodeTVA    = (TStringField*) ptblHI2Np1->FieldByName(strfHI_CodeTVA);
    pfldHINp1TauxTVA    = (TFloatField*) ptblHI2Np1->FieldByName(strfHI_TauxTVA);
    pfldHINp1Designation = (TStringField*) ptblHI2Np1->FieldByName(strfHI_Designation);
    pfldHI2Np1AutoID    = (TIntegerField*) ptblHI2Np1->FieldByName(strfHI_AutoID);
    pfldHINp1AutoID     = (TIntegerField*) ptblHINp1->FieldByName(strfHI_AutoID);

    Tag = TAG(215);
    try
      {
        pBarre->MessageInfo = "Suppression des écritures d'inventaires N";
        tblINVR->EmptyTable();
      }
    catch (...)
      {//On n'arrive pas à supprimer les INVR, c'est pas grave, on continue quand même
      }

    try {
      ///////////////////////////////////////////////////////////////////////////////
      // Reprise des comptes 1 à 5 (et calcul du résultat et MAJ des soldes du PC) //
      ///////////////////////////////////////////////////////////////////////////////
      // L'ID d'écriture d'"A Nouveaux" est toujours 1
      // => Préparation : . Filtrage du PC sur les comptes 1 à 5
      //                  . Tri du HI pour une reprise "par compte"
      #if (PCTYPEENR_COMPTE != 0 )
        #error *** (PCTYPEENR_COMPTE != 0 ) => Revoir le code suivant... ***
      #endif
      Tag = TAG(193); IndexName = striHI_Comptes;
      Tag = TAG(194); ptblPC->PushFilter(fid, szfPC_Compte ">='1' AND " szfPC_Compte "<'6' AND " szfPC_TypeEnr "=0");

      Tag = TAG(195);
      pBarre->MessageInfo = "Report des à nouveaux dans le journal \"" + strJnlANouveau + "\"";
      pBarre->Max         = ptblPC->RecordCount;

      // => Reprise (des comptes mouvementés)
      Tag = TAG(196);
      for(; !ptblPC->Eof; (*pBarre)++, ptblPC->Next())
        if(!pfldPCDebit->IsNull || !pfldPCCredit->IsNull)
        {
          AnsiString strPCCompte(pfldPCCompte->AsString);

          // => MAJ du résultat
          curResultat += curPCSolde = (pfldPCDebit->AsCurrency - pfldPCCredit->AsCurrency);

          if (ANEnDetail && pfldPCRANDetaille->AsBoolean)
          { // Compte réputé "Report A Nouveau Détaillé"
            // => On reprend le détail uniquement non lettré sur N
            Tag = TAG(197);
            if (FindKey(ARRAYOFCONST((strPCCompte)))/*GotoKey()/*Locate(strfHI_Compte,strPCCompte,_loNormal)*/)
            { // Ce compte a bien un détail dans l'histo
              // => On reprend son détail N, non lettré sur N en "A Nouveau détaillé"
              //    (attention: le détail non lettré peut avoir une origine dans N-x par rapport à l'exercice à cloturer)
              //unsigned uFlags;
              bool ContientDuLettrageACheval;
              Currency SoldeNDuCompte;
              SoldeNDuCompte = 0.0;
              ContientDuLettrageACheval = false;
              do
                {
                  if (pfldDateImputation->AsDateTime >= dateDebExNp1)
                    break;
                  if (pfldCrediteur->AsBoolean)
                    SoldeNDuCompte -= pfldMontant->AsCurrency;
                  else
                    SoldeNDuCompte += pfldMontant->AsCurrency;
                  if (EstLettreNp1)
                    {
                      ContientDuLettrageACheval = true;
                      break;
                    }
                  Next();
                }
              while (!Eof && (pfldCompte->AsString == strPCCompte));
              FindKey(ARRAYOFCONST((strPCCompte)));
              /* Demandé par Chantal le 08/08/01
                Si le solde N == 0.0 et pas de lettrage à cheval (sur N et N+1), on ne reprend pas le détail.
              */
              if (ContientDuLettrageACheval || (SoldeNDuCompte != 0.0))
              do {
                if ((pfldDateImputation->AsDateTime < dateDebExNp1) && (!EstLettreN))
                  if(!((/*uFlags =*/ pfldFlags->AsInteger) & HIFLAGS_EST_ANNULEE))
                  { // Reprise de cette ligne détail significative (non annulée)
                    ASSERT_HI_LINE(this);

                    ptblHINp1->Insert();
                    pfldHINp1IDEcriture->AsInteger = 1;
                    pfldHINp1DateImputation->AsDateTime = dateDebExNp1;
                    pfldHINp1Compte->AsString = strPCCompte;
                    pfldHINp1CodeJournal->AsString = strJnlANouveau;
                    //uFlags &= HIFLAGS_A_NOUVEAU_DETAILLE;  // Origine dans N-x ?
                    //ASSERT(!uFlags || (!pfldRANDateO->IsNull && !pfldRANJournalO->IsNull));

                    if (!pfldDateEcheance->IsNull)
                      pfldHINp1DateEcheance->AsDateTime = pfldDateEcheance->AsDateTime;
                    pfldHINp1Piece->AsString = pfldPiece->AsString;
                    pfldHINp1LibelleOperation->AsString = pfldLibelleOperation->AsString;
                    pfldHINp1MontantO->AsCurrency = pfldMontantO->AsCurrency;
                    pfldHINp1CodeDevise->AsInteger = pfldCodeDevise->AsInteger;
                    if(pfldTauxChange->IsNull)
                      pfldHINp1TauxChange->Clear();
                    else
                      pfldHINp1TauxChange->AsFloat = pfldTauxChange->AsFloat;
                    pfldHINp1Montant->AsCurrency = pfldMontant->AsCurrency;
                    pfldHINp1Crediteur->AsBoolean = pfldCrediteur->AsBoolean;
                    pfldHINp1Lettrage->AsString = pfldLettrage->AsString;
                    pfldHINp1FlagLettrage->AsInteger = pfldFlagLettrage->AsInteger;
                    pfldHINp1Flags->AsInteger = HIFLAGS_NORMALE;// | HIFLAGS_A_NOUVEAU_DETAILLE;
                    pfldHINp1ModePaiement->AsInteger = pfldModePaiement->AsInteger;
                    pfldHINp1IDImage->AsString = pfldIDImage->AsString;
                    pfldHINp1Reviseur->AsInteger = pfldReviseur->AsInteger;
                    pfldHINp1Reference->AsInteger = pfldReference->AsInteger;
                    ptblHINp1->Post();
                    ptblHI2Np1->Insert();
                    pfldHI2Np1AutoID->AsInteger = pfldHINp1AutoID->AsInteger;
                    pfldHINp1RANDateO->AsDateTime = (!pfldRANDateO->IsNull ? pfldRANDateO : pfldDateImputation)->AsDateTime;
                    pfldHINp1RANJournalO->AsString = (!pfldRANJournalO->IsNull ? pfldRANJournalO : pfldCodeJournal)->AsString;
                    pfldHINp1PieceExterne->AsString = pfldPieceExterne->AsString;
                    pfldHINp1NatPiece->AsString = pfldNatPiece->AsString;
                    pfldHINp1RAOData->AsString = pfldRAOData->AsString;
                    if(pfldHINp1DateDebPeriode && pfldDateDebPeriode && !pfldDateDebPeriode->IsNull)
                      pfldHINp1DateDebPeriode->AsDateTime = pfldDateDebPeriode->AsDateTime;
                    if(pfldHINp1DateFinPeriode && pfldDateFinPeriode && !pfldDateFinPeriode->IsNull)
                      pfldHINp1DateFinPeriode->AsDateTime = pfldDateFinPeriode->AsDateTime;
                    pfldHINp1RAOIDLigne->AsInteger = TENCOIDECRITURE(TE_ANOUVEAUX);
                    if (!pfldQuantite->IsNull)
                      pfldHINp1Quantite->AsFloat = pfldQuantite->AsFloat;
                    pfldHINp1Banque->AsString = pfldBanque->AsString;
                    pfldHINp1CodeAnalytique->AsString = pfldCodeAnalytique->AsString;
                    ptblHI2Np1->Post();

                    ASSERT_HI_LINE(ptblHINp1);
                  }
                Next();
              } while(!Eof && (pfldCompte->AsString == strPCCompte));
            }
          }
          else
            {
              if (curPCSolde != 0)
                { // Compte non réputé "Report A Nouveau Détaillé" avec solde non nul
                  // => On créé un solde d'"A Nouveau" dans le journal spécifié en devise du dossier
                  Tag = TAG(198);
                  ptblHINp1->Insert();
                  pfldHINp1DateImputation->AsDateTime = dateDebExNp1;
                  pfldHINp1Compte->AsString = strPCCompte;
                  pfldHINp1CodeJournal->AsString = strJnlANouveau;
                  pfldHINp1IDEcriture->AsInteger = 1;
                  pfldHINp1LibelleOperation->AsString = _strIntiuleANouveau;
                  if(bDossierFRF)
                  { pfldHINp1CodeDevise->AsInteger = DeviseCodeFranc;
                    pfldHINp1TauxChange->Clear();                 // Pas de taux de change pour le FRF car monnaie zone euro
                  }
                  else
                    {
                       pfldHINp1CodeDevise->AsInteger = DeviseCodeEuro;
                       pfldHINp1TauxChange->AsFloat = 1.0;
                    }
                  if(curPCSolde < 0)
                  { pfldHINp1Crediteur->AsBoolean = true;
                    curPCSolde = -curPCSolde;
                  }
                  else
                    {
                      ASSERT(!pfldHINp1Crediteur->AsBoolean);
                    }
                  pfldHINp1MontantO->AsCurrency = curPCSolde;
                  pfldHINp1Montant->AsCurrency = curPCSolde;
                  pfldHINp1Flags->AsInteger = HIFLAGS_NORMALE;
                  ptblHINp1->Post();

                  ASSERT_HI_LINE(ptblHINp1);
                  ptblHI2Np1->Insert();
                  pfldHI2Np1AutoID->AsInteger = pfldHINp1AutoID->AsInteger;
                  pfldHINp1RANDateO->Clear();    //Pas de date d'origine pour un regroupement
                  pfldHINp1RANJournalO->Clear(); //Pas de journal d'origine pour un regroupement
                  pfldHINp1RAOIDLigne->AsInteger = TENCOIDECRITURE(TE_ANOUVEAUX);
                  ptblHI2Np1->Post();
                }
            }
        }

      // => Fin de la reprise des comptes 1 à 5
      Tag = TAG(199); ptblPC->PopFilter(fid);
    } catch(Exception& e) {
      ptblPC->PopFilter(fid);
      throw EUser(Tag, e);
    }

    ////////////////////////////
    // Résultat de l'exercice //
    ////////////////////////////
    Tag = TAG(200);
    if(curResultat != 0)
    { // Le résultat est non nul
      // => Il va figurer en "A Nouveau"
      ptblHINp1->Insert();
      pfldHINp1IDEcriture->AsInteger  = 1;
      pfldHINp1DateImputation->AsDateTime = dateDebExNp1;
      pfldHINp1CodeJournal->AsString   = strJnlANouveau;
      if(curResultat > 0)
      { // Masse Débits Comptes 1 à 5 > Masse Crédits comptes 1 à 5
        // => L'exercice est bénéficiaire
        pfldHINp1Crediteur->AsBoolean = true;
        ptblPC->CreerCompteStandard(TAGL,CompteResultatBenefice,"Bénéfice de l'exercice");
      }
      else
      { // Masse Débits Comptes 1 à 5 < Masse Crédits comptes 1 à 5
        // => L'exercice est déficiaire
        ASSERT(!pfldHINp1Crediteur->AsBoolean);

        ptblPC->CreerCompteStandard(TAGL,CompteResultatPerte,"Perte de l'exercice");
        curResultat = -curResultat;
      }
      pfldHINp1Compte->AsString = pfldPCCompte->AsString;
      pfldHINp1LibelleOperation->AsString = _strIntiuleANouveau;
      if(bDossierFRF)
      { pfldHINp1CodeDevise->AsInteger = DeviseCodeFranc;
        pfldHINp1TauxChange->Clear();                 // Pas de taux de change pour le FRF car monnaie zone euro
      }
      else {
                       pfldHINp1CodeDevise->AsInteger = DeviseCodeEuro;
                       pfldHINp1TauxChange->AsFloat = 1.0;
      }

      pfldHINp1MontantO->AsCurrency = curResultat;
      pfldHINp1Montant->AsCurrency = curResultat;

      pfldHINp1Flags->AsInteger = HIFLAGS_NORMALE;
      ptblHINp1->Post();
      ASSERT_HI_LINE(ptblHINp1);
      ptblHI2Np1->Insert();
      pfldHI2Np1AutoID->AsInteger = pfldHINp1AutoID->AsInteger;
      pfldHINp1RAOIDLigne->AsInteger = TENCOIDECRITURE(TE_ANOUVEAUX);
      ptblHI2Np1->Post();
    }
  (*pBarre) = 0;
  pBarre->MessageInfo = "Reprise des écritures N+1";
  int IDEcriture(-1),NbIDEcriture(1);
  FilterID FiltreID(FID_NUL);
  AnsiString AncienIndexName(IndexName);
  try
    {                                            //On reprend les écriture N+1
      PushFilter(FiltreID,strfHI_DateImputation + ">'" + dateFinExN.DateString() + "'"); //On ne prend que les écritures sur N+1
      IndexName = striHI_IDEcritures;            //On tri par écriture pour les reprendre dans le même ordre
      First();
      pBarre->Max = RecordCount;
      while (!Eof)
        {
          if (pfldIDEcriture->AsInteger != IDEcriture)
            {
              IDEcriture = pfldIDEcriture->AsInteger;
              NbIDEcriture++;
            }
          ptblHINp1->Append();
          pfldHINp1IDEcriture->AsInteger = NbIDEcriture;
          pfldHINp1DateImputation->AsDateTime = pfldDateImputation->AsDateTime;
          if (!pfldDateEcheance->IsNull)
            pfldHINp1DateEcheance->AsDateTime = pfldDateEcheance->AsDateTime;
          if (!pfldDateEP->IsNull)
            pfldHINp1DateEP->AsDateTime = pfldDateEP->AsDateTime;
          if (!pfldDateExport->IsNull)
            pfldHINp1DateExport->AsDateTime = pfldDateExport->AsDateTime;
          pfldHINp1Compte->AsString = pfldCompte->AsString;
          pfldHINp1CodeJournal->AsString = pfldCodeJournal->AsString;
          pfldHINp1Piece->AsString = pfldPiece->AsString;
          pfldHINp1LibelleOperation->AsString = pfldLibelleOperation->AsString;
          pfldHINp1MontantO->AsCurrency = pfldMontantO->AsCurrency;
          pfldHINp1CodeDevise->AsInteger = pfldCodeDevise->AsInteger;
          if(pfldTauxChange->IsNull)
            pfldHINp1TauxChange->Clear();
          else
            pfldHINp1TauxChange->AsFloat = pfldTauxChange->AsFloat;
          pfldHINp1Montant->AsCurrency = pfldMontant->AsCurrency;
          pfldHINp1Crediteur->AsBoolean = pfldCrediteur->AsBoolean;
          pfldHINp1Lettrage->AsString = pfldLettrage->AsString;
          pfldHINp1FlagLettrage->AsInteger = pfldFlagLettrage->AsInteger;
          pfldHINp1Flags->AsInteger = pfldFlags->AsInteger & ~HIFLAGS_LETTRAGE_EST_MODIFIE;
          pfldHINp1ModePaiement->AsInteger = pfldModePaiement->AsInteger;
          pfldHINp1IDImage->AsString = pfldIDImage->AsString;
          pfldHINp1Reviseur->AsInteger = pfldReviseur->AsInteger;
          pfldHINp1Reference->AsInteger = pfldReference->AsInteger;

          ASSERT_HI_LINE(ptblHINp1);

          ptblHINp1->Post();
          
          ptblHI2Np1->Append();
          pfldHI2Np1AutoID->AsInteger = pfldHINp1AutoID->AsInteger;
          pfldHINp1IDEcriturePart->AsString = pfldIDEcriturePart->AsString;
          pfldHINp1PieceExterne->AsString = pfldPieceExterne->AsString;
          pfldHINp1NatPiece->AsString = pfldNatPiece->AsString;
          pfldHINp1RAOIDLigne->AsInteger = pfldRAOIDEcriture->AsInteger;
          pfldHINp1RAOData->AsString = pfldRAOData->AsString;
          if(pfldHINp1DateDebPeriode && pfldDateFinPeriode && !pfldDateFinPeriode->IsNull)
            pfldHINp1DateDebPeriode->AsDateTime = pfldDateDebPeriode->AsDateTime;
          if(pfldHINp1DateFinPeriode && pfldDateFinPeriode && !pfldDateFinPeriode->IsNull)
            pfldHINp1DateFinPeriode->AsDateTime = pfldDateFinPeriode->AsDateTime;
          if (!pfldQuantite->IsNull)
            pfldHINp1Quantite->AsFloat = pfldQuantite->AsFloat;
          pfldHINp1Banque->AsString = pfldBanque->AsString;
          pfldHINp1CodeAnalytique->AsString = pfldCodeAnalytique->AsString;
          pfldHINp1CodeTVA->AsString = pfldCodeTVA->AsString;
          if (!pfldTauxTVA->IsNull)
            pfldHINp1TauxTVA->AsFloat = pfldTauxTVA->AsFloat;
          pfldHINp1Designation->AsString = pfldDesignation->AsString;
          ptblHI2Np1->Post();
          Next();
          (*pBarre)++;
        }
      IndexName = AncienIndexName;
      PopFilter(FiltreID);
    }
  catch(Exception &e)
    {
      ptblHINp1->Cancel();
      ptblHI2Np1->Cancel();
      IndexName = AncienIndexName;
      PopFilter(FiltreID);
      throw EUser(TAG(201),e);
    }
#pragma message @@@ Recalculer les IDEcritures ........................@@@

    try {
      //////////////////////////////////////////////
      // Génération du journal de contrepassation //
      //////////////////////////////////////////////
      int  nNoEcriture;       // Le n° d'une écriture de contrepassation dans le HI N+1
      int  nNoPrevEcriture;   // Le n° de la dernière écriture contrepassée
      bool bCtrPassDotToRepr; // TRUE s'il faut contrepasser les comptes de dotation en comptes de reprises pour l'écriture courante

      // => Préparation : . Les ID des écritures contrepassées vont être renumérotés à partir de 2
      //                  . On filtre le journal "INVR" sur le drapeau HIFLAGS_A_CONTREPASSER en le triant
      //                    par écriture (ce journal ne peut être rempli que par les assistants)
#pragma message @@@ Voir si on commence bien ici ........................@@@
      nNoEcriture       = NbIDEcriture;
      nNoPrevEcriture   = 0;
      bCtrPassDotToRepr = false;
      #if HIFLAGS_A_CONTREPASSER != 0x10
       #error *** (HIFLAGS_A_CONTREPASSER != 16 ) : Revoir le code suivant... ***
      #endif
      Tag = TAG(202); IndexName = striHI_IDEcritures;
      Tag = TAG(203); PushFilter(fid,"(" szfHI_CodeJournal "='INVR' AND " szfHI_Flags ">=16) OR " szfHI_CodeJournal "='INVC'");

      // => Initialisation de la progression
      Tag = TAG(204);
      pBarre->MessageInfo = "Création du journal de contrepassation \"CONT\"";
      pBarre->Max         = RecordCount;

      // => Transfert dans le journal de contrepassation
      Tag = TAG(205);
      for(; !Eof; (*pBarre)++, Next())
        if (!(pfldFlags->AsInteger & HIFLAGS_EST_ANNULEE) &&
            ((pfldFlags->AsInteger & HIFLAGS_A_CONTREPASSER) || AnsiSameText(pfldCodeJournal->AsString,"INVC")))
        { // Cette ligne est significative (non annulée) et a contrepasser
          #ifdef _DEBUG
            if (!LIGNE_EST_ECART_ARRONDI(pfldFlags->AsInteger) && !LIGNE_EST_ECART_CHANGE(pfldFlags->AsInteger))
              {
                if (pfldCodeJournal->AsString != "INVC")
                  {
                    ASSERT(!pfldPiece->IsNull);   // Un assistant à tjs une pièce (code ass + code interne) sauf pour les écarts
                    ASSERT(pfldNatPiece->IsNull); // et ne précise jamais la nature de pièce
                  }
              }
          #endif

          if(nNoPrevEcriture != pfldIDEcriture->AsInteger)
          { // On commence le transfert d'une autre écriture à contrepasser
            // => On incrémente le renumérotage et on assume que les écritures de Stock (code personnel '1') doivent être contrepassées en reprise
            nNoPrevEcriture   = pfldIDEcriture->AsInteger;
            #pragma message("*** Clôture: Pas de reprise des dotations des écritures de Stock.... ***" )

            ASSERT(!bCtrPassDotToRepr);

            nNoEcriture++;
          }

          // Transfert de la ligne
          ptblHINp1->Insert();
          pfldHINp1IDEcriture->AsInteger  = nNoEcriture;
          pfldHINp1DateImputation->AsDateTime = dateDebExNp1;
          pfldHINp1Compte->AsString   = ptblPC->CreerCompteRepriseDeDotation(pfldCompte->AsString, bCtrPassDotToRepr);
          pfldHINp1CodeJournal->AsString   = "CONT";
          pfldHINp1Piece->AsString   = pfldPiece->AsString;
          pfldHINp1LibelleOperation->AsString   = pfldLibelleOperation->AsString;
          pfldHINp1CodeDevise->AsInteger = pfldCodeDevise->AsInteger;
          if (pfldTauxChange->IsNull)
            pfldHINp1TauxChange->Clear();
          else
            pfldHINp1TauxChange->AsFloat = pfldTauxChange->AsFloat;
          pfldHINp1MontantO->AsCurrency = pfldMontantO->AsCurrency;
          pfldHINp1Montant->AsCurrency = pfldMontant->AsCurrency;
          pfldHINp1Crediteur->AsBoolean = !pfldCrediteur->AsBoolean; //On inverse le D/C pour une ligne de contrepassation
          pfldHINp1Flags->AsInteger  = HIFLAGS_NORMALE | (pfldFlags->AsInteger & (HIFLAGS_ECART_ARRONDI | HIFLAGS_ECART_CHANGE));//Il faut garder le flag d'écart
          ptblHINp1->Post();

          ASSERT_HI_LINE(ptblHINp1);
          ptblHI2Np1->Insert();
          pfldHI2Np1AutoID->AsInteger = pfldHINp1AutoID->AsInteger;
          pfldHINp1PieceExterne->AsString = pfldPieceExterne->AsString;
          pfldHINp1RAOData->AsString   = pfldRAOData->AsString;
          if(pfldHINp1DateDebPeriode && pfldDateFinPeriode && !pfldDateFinPeriode->IsNull)
            pfldHINp1DateDebPeriode->AsDateTime = pfldDateDebPeriode->AsDateTime;
          if(pfldHINp1DateFinPeriode && pfldDateFinPeriode && !pfldDateFinPeriode->IsNull)
            pfldHINp1DateFinPeriode->AsDateTime = pfldDateFinPeriode->AsDateTime;
          ptblHI2Np1->Post();
        }

      // Fin de la génération du journal de contrepassation
      Tag = TAG(206); PopFilter(fid);
    } catch(Exception& e) {
      PopFilter(fid);
      throw EUser(Tag, e);
    }
    IndexName = EmptyStr;

    pBarre->MessageInfo = "Reclassement des lettrages";
    ptblHINp1->ReclasserLettrages(EmptyStr,pBarre);

    /////////////////////////////////////////////////////////
    // Ecriture des dernières modifications dans le HI N+1 //
    /////////////////////////////////////////////////////////
    Tag = TAG(207); ptblHINp1->FlushBuffers();



    /////////////////////////////////
    // Clôture du PC lié au HI N+1 //
    /////////////////////////////////
    // => Tri du HI N+1 par comptes
    ASSERT(!ptblPC->Filtered);
    ASSERT(ptblPC->IndexName.IsEmpty());
    
    Tag = TAG(208); ptblHINp1->IndexName = striHI_Comptes;

    // => Initialisation de la progression
    Tag = TAG(209);
    pBarre->MessageInfo = "Génération du bilan d'ouverture";
    pBarre->Max         = ptblPC->RecordCount;

    // => Clôture du PC : . Décalage des soldes N-x et calcul des soldes N des comptes
    //                    . RAZ des visas des Comptes et des PT
    Tag = TAG(210); ptblPC->First();
    for(; !ptblPC->Eof; (*pBarre)++, ptblPC->Next())
    {
      ptblPC->Edit();
      if(ptblPC->EstUnCompte)
      { // Décalage Soldes N-3 su N-4, N-2 sur N-3 et N-1 sur N-2
        if(pfldPCSoldeNm3->IsNull)
        { // Pas de solde en N-3 => Pas de solde en N-4
          pfldPCSoldeNm4->Clear();
        }
        else
        { // Solde en N-3 => Décalage sur N-4
          pfldPCSoldeNm4->AsCurrency = pfldPCSoldeNm3->AsCurrency;
        }
        if(pfldPCSoldeNm2->IsNull)
        { // Pas de solde en N-2 => Pas de solde en N-3
          pfldPCSoldeNm3->Clear();
        }
        else
        { // Solde en N-2 => Décalage sur N-3
          pfldPCSoldeNm3->AsCurrency = pfldPCSoldeNm2->AsCurrency;
        }
        if(pfldPCSoldeNm1->IsNull)
        { // Pas de solde en N-1 => Pas de solde en N-2
          pfldPCSoldeNm2->Clear();
        }
        else
        { // Solde en N-1 => Décalage sur N-2
          pfldPCSoldeNm2->AsCurrency = pfldPCSoldeNm1->AsCurrency;
        }

        // Décalage Solde N sur N-1
        if(pfldPCDebit->IsNull && pfldPCCredit->IsNull)
        { // Pas de solde en N => Pas de solde en N-1
          pfldPCSoldeNm1->Clear();
        }
        else
        { // Solde en N => Décalage sur N-1
          pfldPCSoldeNm1->AsCurrency = pfldPCDebit->AsCurrency - pfldPCCredit->AsCurrency;
        }

        // Calcul des nouvelles masses Débit et Crédit N
        bool       bDebits  = false;
        bool       bCredits = false;
        Currency   curDebits;
        Currency   curCredits;
        AnsiString strPCCompte(pfldPCCompte->AsString);

        if(ptblHINp1->FindKey(ARRAYOFCONST((strPCCompte)))/*ptblHINp1->Locate(strfHI_Compte, strPCCompte, Compta::_loNormal)*/)
        { // Calcul des masses Débit/Crédit du compte sur N+1
          do {
            if(pfldHINp1Crediteur->AsBoolean) { bCredits = true; curCredits += pfldHINp1Montant->AsCurrency;}
            else                              { bDebits  = true; curDebits  += pfldHINp1Montant->AsCurrency;}
            ptblHINp1->Next();
          } while(!ptblHINp1->Eof && (pfldHINp1Compte->AsString == strPCCompte));
        }
        pfldPCDebitSituation->Clear();
        pfldPCCreditSituation->Clear();
        if (bDebits)
          {
            pfldPCDebit->AsCurrency = curDebits;
            pfldPCDebitTotal->AsCurrency = curDebits;
          }
        else
          {
            pfldPCDebit->Clear();
            pfldPCDebitTotal->Clear();
          }
        if (bCredits)
          {
            pfldPCCredit->AsCurrency = curCredits;
            pfldPCCreditTotal->AsCurrency = curCredits;
          }
        else
          {
            pfldPCCredit->Clear();
            pfldPCCreditTotal->Clear();
          }
      }
      pfldPCVisas->AsInteger = TTablePC::PCVISA_AUCUN;        // RAZ des visas (Compte ou PT)
    }
    Tag = TAG(211);
    pBarre->MessageInfo = "Recalcul des soldes des comptes collectifs";
    ptblPC->CalculerSoldesCollectifs();
    ptblPC->FlushBuffers();
    Tag = TAG(212);
    pBarre->MessageInfo = "Suppression des visas des consignes";
    (*pBarre) = 0;
    TTablePT *tblPT;
    try
      {
        tblPT = 0;
        tblPT = new TTablePT(0);
        if (tblPT->Exists)
          {
            tblPT->Open();
            tblPT->First();
            pBarre->Max = tblPT->RecordCount;
            while (!tblPT->Eof)
              {
                tblPT->ViserConsigne(false);
                tblPT->Next();
                (*pBarre)++;
              }
            tblPT->Close();
          }
        delete tblPT;
        tblPT = 0;
      }
    catch (Exception &e)
      {
        delete tblPT;
        throw EUser(TAGL,e);
      }
    Tag = TAG(213);
    ptblHINp1->IndexName = EmptyStr;
#pragma message @@@ Voir si c est bon ici .........................................  @@@
    pBarre->MessageInfo = "Modification du lettrage N+1";
    ptblHINp1->SupprimerAncienLettrageNp1(ptblPC,dateFinExNp1,pBarre);
    pBarre->MessageInfo = "Génération des références d'écriture";
    ptblHINp1->GenerateReferences();

    ASSERT(!tblNotes->Active);
    ASSERT(!tblNotes->Filtered);
    ASSERT(!tblNotes->MasterSource);

    Tag = TAG(214);
    pBarre->MessageInfo = "Clôture des notes de contrôle";
    try
      {
        if (tblNotes->Exists)
          {
            tblNotes->Open();
            pBarre->Max = tblNotes->RecordCount + 1;
            tblNotesReportNp1 = (TBooleanField *)tblNotes->FieldByName("ReportNp1");
            tblNotes->First();
            while (!tblNotes->Eof)
              {
                if (tblNotesReportNp1->AsBoolean)
                  tblNotes->Next();
                else
                  tblNotes->Delete();
                (*pBarre)++;
              }
            tblNotes->Close();
          }
      }
    catch (Exception &e)
      {
        throw EUser(Tag,e);
      }
  } catch(Exception& e) {
               IndexName = EmptyStr;
    ptblHINp1->IndexName = EmptyStr;
    throw EUser(Tag,e);
  }
 } /* TTableHI::Cloturer() */


 //------------------------------------------------------------------------------
 //
 //  Obtient le solde de la ligne courante [ = Debit - Credit ]
 //
 // Solde d'une ligne d'écriture = Montant signé dans le but de calculer un solde
 Currency __fastcall TTableHI::ObtenirSolde()
 {
  TCurrencyField* pfldMontant;

  ASSERT(State == dsBrowse);

  pfldMontant = (TCurrencyField*)FieldByName(strfHI_Montant);
  if(EstCrediteur)
  {
    return(-pfldMontant->AsCurrency);
  }
  else
  {
    return(pfldMontant->AsCurrency);
  }
 } /* TTableHI::ObtenirSolde() */


 /*----------------------------------------------------------------------------*\
 ------------- TTableHI::CreerIDNouvelleEcriture() ------------------------------
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette fonction retourne un ID d'écriture valable pour identifier une      -
 - nouvelle écriture.                                                           -
 -                                                                              -
 - Retour :                                                                     -
 -   Un nouvel ID d'écriture.                                                   -
 \*----------------------------------------------------------------------------*/
 int __fastcall TTableHI::CreerIDNouvelleEcriture()
 {
  int     nIDEcr   = 0;
  TQuery *qryIDEcr = new TQuery( NULL);

  qryIDEcr->DatabaseName = DatabaseName;
  qryIDEcr->SQL->Text    = "SELECT MAX(" szfHI_IDEcriture ") FROM '" + TableName + "'";
  qryIDEcr->Open();
  nIDEcr = qryIDEcr->Fields->Fields[0]->AsInteger;
  qryIDEcr->Close();
  // Et vérifie qu'il n'existe pas un ID écriture plus grand ds INVR$$H
  qryIDEcr->SQL->Text    = "SELECT MAX(" szfHI_IDEcriture ") FROM INVR$$H";
  qryIDEcr->Open();
  if( qryIDEcr->Fields->Fields[0]->AsInteger>=nIDEcr) nIDEcr = qryIDEcr->Fields->Fields[0]->AsInteger;
  qryIDEcr->Close();
  delete qryIDEcr;

  return nIDEcr + 1;

 } /* TTableHI::CreerIDNouvelleEcriture() */


 /*----------------------------------------------------------------------------*\
 ------------- TTableHI::RAZCptNonMouvementes() ---------------------------------
 --------------------------------------------------------------------------------
 -                     L'ENREGISTREMENT COURANT EST MODIFIE                     -
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette procédure permet de supprimer, dans le PC associé à cet historique, -
 - toute de trace de mouvement sur une liste de compte donnée.                  -
 -                                                                              -
 - Paramètres :                                                                 -
 -   ptblPC : PC lié au HI.                                                     -
 -   lstcpt : Liste de comptes qui ne sont plus - a priori - mouvementés dans   -
 -            cet historique.                                                   -
 -                                                                              -
 - Note : Lorsqu'un compte de la liste n'est plus mouvementé dans cet historique-
 -        on "clear" ses totaux Débit/Crédit dans le PC associé pour indiquer à -
 -        partir du PC, qu'aucun mouvement sur ce compte n'existe dans ce HI.   -
 \*----------------------------------------------------------------------------*/
 void __fastcall TTableHI::RAZCptNonMouvementes(TTablePC*     ptblPC,
                                                 TListComptes& lstcpt)
 {
  TStringField*   pfldCompte;   // Le champ "N° de compte"
  TCurrencyField* pfldPCDebit;  // "    "      "Débit"     du PC
  TCurrencyField* pfldPCCredit; // "    "      "Crédit"    "  "

  ASSERT(!Filtered);
  ASSERT(ptblPC && ptblPC->Active);
  ASSERT(!ptblPC->Filtered);


  //////////////////////////////////////////////
  // Vérification de l'utilité de l'opération //
  //////////////////////////////////////////////
  if(lstcpt.empty())
    return;


  try {
    IndexName    = striHI_Comptes;
    pfldCompte   = (TStringField*)FieldByName(strfHI_Compte);
    pfldPCDebit  = (TCurrencyField*)ptblPC->FieldByName(TTablePC::strfPC_Debit);
    pfldPCCredit = (TCurrencyField*)ptblPC->FieldByName(TTablePC::strfPC_Credit);
    lstcpt.unique();


    ////////////////////////////////////////////////////////
    // Recherche des comptes qui ne sont plus mouvementés //
    ////////////////////////////////////////////////////////
    for(std::list<AnsiString>::iterator iter = lstcpt.begin();
         iter != lstcpt.end();
         iter++
       )
     { // Recherche d'une ligne du HI qui fait mouvementer le compte détruit
       SetKey();
       pfldCompte->AsString = *iter;
       if(!GotoKey())
       { // Le compte détruit n'est plus mouvementé dans le HI
         // => RAZ de ses soldes dans le PC (ainsi, l'utilisateur voit qu'il n'y a plus de mouvement sur ce compte)
         VERIFY(ptblPC->AllerSurLeCompte(*iter));
         ASSERT((pfldPCDebit->IsNull || (pfldPCDebit->AsCurrency == (int)0)) &&
                 (pfldPCCredit->IsNull || (pfldPCCredit->AsCurrency == (int)0)));

         ptblPC->Edit();
         pfldPCDebit->Clear();
         pfldPCCredit->Clear();
         ptblPC->Post();
       }
     }
     ptblPC->FlushBuffers();
   } catch(...) {
     // Erreur de d'effacement des Débit/Crédits des comptes inutilisés dans le PC
     // => On ignore l'erreur
   }
   IndexName = EmptyStr;
 } /* TTableHI::RAZCptNonMouvementes() */


 /******************************************************************************\
 ************* TTableHI::AnnulerEcriture() **************************************
 ********************************************************************************
 *                     L'ENREGISTREMENT COURANT EST MODIFIE                     *
 ********************************************************************************
 *                                                                              *
 *    Cette procédure permet d'annuler une écriture i.e. d'annuler toutes ses   *
 * lignes (on obtient donc une nouvelle écriture qui ne comporte que des lignes *
 * annulées ou bien qui est vide si aucune des lignes de l'écriture à annuler   *
 * n'a été importée).                                                           *
 *                                                                              *
 * Paramètres :                                                                 *
 *   nID    : ID de l'écriture à annuler                                        *
 *   ptblPC : PC lié au HI.                                                     *
 \******************************************************************************/
 bool __fastcall TTableHI::AnnulerEcriture( int nID, TTablePC* ptblPC, CTable *ptblHI2, int *nNewID /* = NULL */,
                                            bool bSupprLettrage /* = true */)
 {
   if( EstEcriturePointee( nID)) {
     ::EICErreur( "Vous ne pouvez pas détruire cette écriture car elle contient au moins une ligne qui est pointée.");
     return false;
   }
   if( EstEcritureValidee( nID)) {
     ::EICErreur( "Vous ne pouvez pas détruire cette écriture car elle est validée.");
     return false;
   }
   AnnulerEcritureSansTest( nID, ptblPC,ptblHI2, nNewID, bSupprLettrage);
   return true;
 }
 void __fastcall TTableHI::AnnulerEcritureSansTest( int nID, TTablePC* ptblPC, CTable *ptblHI2, int *nNewID, bool bSupprLettrage)
 {
  TListComptes lstcptDetruits; // Liste des comptes dont les lignes ont été détruites physiquement
  int          nIDEcrAnnulee;  // ID de l'écriture annulée (écriture rectifiée qui ne contiendra que des lignes annulées de l'écriture d'origine)
  FilterID     fidEcriture;    // Filtre de l'écriture à annuler
  bool         bTmp;           // Variable temporaire
  IndexName = EmptyStr;

  ASSERT(!Filtered && IndexName.IsEmpty());
  ASSERT(ptblPC);

  nIDEcrAnnulee = CreerIDNouvelleEcriture();
  fidEcriture   = FID_NUL;


  try {
    /////////////////////////////////////////////////////
    // Réduction du HI à l'écriture qui nous intéresse //
    /////////////////////////////////////////////////////
    PushFilter(fidEcriture, szfHI_IDEcriture "=" + AnsiString(nID));
    ASSERT(Filtered && Bof);

    //////////////////////////////
    // Annulation de l'écriture //
    //////////////////////////////
    if( bSupprLettrage) m_bDelLettrage = true;
    while(!Eof)
    {
      if(EstUneLigneAnnulee)
        TransfererLigne(ptblHI2,nIDEcrAnnulee);
      else
        AnnulerLigne(ptblPC,ptblHI2, nIDEcrAnnulee, bTmp, lstcptDetruits);
      // First(); // On se remet au début de l'écriture pour effectuer l'annulation dans l'ordre (à cause des lignes importées)
      // Suppression du First() car plantage dans certain cas
    }
    if( bSupprLettrage) m_bDelLettrage = false;
    ASSERT(IsEmpty());


    //////////////////////////////////////
    // Annulation de la réduction du HI //
    //////////////////////////////////////
    PopFilter(fidEcriture); ASSERT(!Filtered);


    ////////////////////////////////////////////////////////
    // RAZ des comptes du PC qui ne sont plus mouvementés //
    ////////////////////////////////////////////////////////
    RAZCptNonMouvementes(ptblPC, lstcptDetruits);


    //////////////////////////////////
    // Validation des modifications //
    //////////////////////////////////
    ChangeIDEcriture( nIDEcrAnnulee, nID); nIDEcrAnnulee = nID;
    FlushBuffers();

  } catch(Exception& e) {
    PopFilter(fidEcriture); ASSERT(!Filtered);
    throw EUser(TAG(220), e);
  }

  if ( nNewID) *nNewID = nIDEcrAnnulee;
 } /* TTableHI::AnnulerEcriture() */



 /******************************************************************************\
 ************* TTableHI::ResultatSituation() ************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction calcule le résultat comptable sur une période de situation.*
 *                                                                              *
 * Paramètres :                                                                 *
 *   dateDebutSituation/dateFinSituation : Bornes de la période de situation.   *
 *                                                                              *
 * Retour :                                                                     *
 *   Le résultat comptable sur la période indiquée.                             *
 \******************************************************************************/
Currency __fastcall TTableHI::ResultatSituation(const TDateTime &DateSituation,bool AvecBarre)
{
  CBarre *Barre;
  char PremierChiffre;

  ASSERT(State == dsBrowse);

  TDataSource *AncienMasterSource(MasterSource); //La table ne doit pas être esclave ...
  bool bAncienFiltered(Filtered);
  AnsiString strAncienBookmark(Bookmark);
  TCurrencyField *pfldMontant((TCurrencyField*)FieldByName(strfHI_Montant));
  TBooleanField *pfldEstCrediteur((TBooleanField*)FieldByName(strfHI_EstCrediteur));
  TStringField *pfldCompte((TStringField *)FieldByName(strfHI_Compte));
  TDateTimeField *pfldDateImputation((TDateTimeField *)FieldByName(strfHI_DateImputation));
  Currency curResultat;
  try
    {
      DisableControls();
      if (AvecBarre)
        {
          try
            {
              Barre = new CBarre();
              Barre->Messages = "Initialisation\n"
                                "Calcul à partir du grand livre";
              Barre->Titre = "Calcul du résultat à la date de situation";
              Barre->Open();
              (*Barre) = 0;
            }
          catch (...)
            {
              AvecBarre = false;
            }
        }
      MasterSource = 0;
      Filtered = false;
      if (AvecBarre)
        {
          Barre->NextMessage();
          Barre->Max = RecordCount;
        }
      First();
      while(!Eof)
        {
          PremierChiffre = pfldCompte->AsString[1];
          if ((PremierChiffre > '5') && (PremierChiffre < '8') && (pfldDateImputation->AsDateTime <= DateSituation))
            {
              if(pfldEstCrediteur->AsBoolean)
                curResultat += pfldMontant->AsCurrency;
              else
                curResultat -= pfldMontant->AsCurrency;
            }
          Next();
          if (AvecBarre)
            (*Barre)++;
        }
      EnableControls();
      Filtered = bAncienFiltered;
      Bookmark = strAncienBookmark;
      MasterSource = AncienMasterSource;
      if (AvecBarre)
        {
          Barre->Close();
          delete Barre;
          Barre = 0;
        }
    }
  catch(...)
    {
      EnableControls();
      Filtered = bAncienFiltered;
      Bookmark = strAncienBookmark;
      MasterSource = AncienMasterSource;
      delete Barre;
      Barre = 0;
      return -1;
    }
  return curResultat;
} /* TTableHI::ResultatSituation() */


 class CDBRecord
 {
  private:
   char* m_pRec;

  public:
   __fastcall CDBRecord();
   virtual __fastcall ~CDBRecord();

          CDBRecord& __fastcall operator<<(TTable& tbl);
   friend TTable&    __fastcall operator<<(TTable& tbl, const CDBRecord& dbrecSrc);
 };

 __fastcall CDBRecord::CDBRecord()
 {
  m_pRec = NULL;
 } /* CDBRecord::CDBRecord() */

 __fastcall CDBRecord::~CDBRecord()
 {
  if(m_pRec != NULL)
    delete[] m_pRec;
 } /* CDBRecord::~CDBRecord() */

 TTable& __fastcall operator<<(TTable& tbl, const CDBRecord& dbrecSrc)
 {
  if(dbrecSrc.m_pRec == NULL)
    EICThrowInvalidArgument(TAG(230));
  if(!memcpy(tbl.ActiveBuffer(), dbrecSrc.m_pRec, tbl.RecordSize))
    EICThrowInvalidArgument(TAG(231));
  return(tbl);
 } /* operator<<() */

 CDBRecord& __fastcall CDBRecord::operator<<(TTable& tbl)
 {
  if(m_pRec == NULL)
    m_pRec = new char[ tbl.RecordSize];
  if(!tbl.GetCurrentRecord(m_pRec))
    EICThrowInvalidArgument(TAG(240));
  return(*this);
 } /* CDBRecord::operator<<() */


 /*----------------------------------------------------------------------------*\
 ------------- TTableHI::AnnulerLigne() -----------------------------------------
 --------------------------------------------------------------------------------
 -                     L'ENREGISTREMENT COURANT EST MODIFIE                     -
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette fonction permet d'annuler la ligne courante (qui est détruite       -
 - physiquement si elle est normale mais qui est annulée (par création d'une    -
 - ligne inverse) si elle est importée).                                        -
 -                                                                              -
 - Paramètres :                                                                 -
 -   ptblPC          : PC lié qu HI (pour MAJ du Débit/Crédit annulé).          -
 -   nIDEcrRectifiee : ID de l'écriture rectifiée qui doit comporter la ligne   -
 -                     et sa ligne annulée.                                     -
 -   bEtaitImportee  : Retourne TRUE si la ligne annulée était importée; FALSE  -
 -                     sinon (i.e. la ligne annulée était normale).             -
 -   lstcptDeleted   : Une liste de n° de comptes à laquelle va s'ajouter le    -
 -                     n° de compte courant si la ligne courante est            -
 -                     phsiquement détruite (cela permet de stocker les comptes -
 -                     dont un mouvement est physiquement supprimé de ce HI).   -
 -                                                                              -
 - Notes : * La ligne courante ne doit pas être un "A Nouveau" au sens Rev'AO.  -
 -         * Si la ligne courante est importée et non annulée elle est          -
 -           transférée telle quelle dans l'écriture rectifiée et marquée comme -
 -           annulée et une ligne inverse est créé - toujours dans l'écriture   -
 -           rectifiée - de façon à annuler la ligne courante; sinon, si elle   -
 -           est normale (i.e. saisie dans la fonction de base) elle est        -
 -           détruite physiquement et son n° de compte est ajouté à la liste    -
 -           passée en paramètre.                                               -
 \*----------------------------------------------------------------------------*/
 void __fastcall TTableHI::AnnulerLigne(TTablePC*     ptblPC,
                                        CTable*       ptblHI2,
                                        int           nIDEcrRectifiee,
                                        bool&         bEtaitImportee,
                                        TListComptes& lstcptDeleted)
 {
  TIntegerField*  pfldFlags;   // Champ    "Flags"
  TCurrencyField* pfldMontant; //   "     "Montant"
  unsigned int    uFlags;      // Valeur du champ "Flags"
  EICTag          tag;
  bool bEstCrediteur, EnregitrementDansHI2;
  TDateTime DateImputation;
  bool bFiltered = Filtered;

  #ifdef _DEBUG
  { ASSERT(State == dsBrowse);
    ASSERT(ptblPC);
    ASSERT(ptblPC->Active);
    ASSERT(ptblHI2);
    ASSERT(ptblHI2->Active);
    ASSERT(ptblHI2->IndexName.IsEmpty());
    ASSERT(nIDEcrRectifiee != IdEcritureNouvelle);                            // Annulation d'une ligne d'écriture nouvelle impossible
    ASSERT(FieldByName(strfHI_CodeDevise)->AsInteger != CODE_DEVISE_DEFAUT); // Annulation d'une ligne "Ecart de change" impossible
  }
  #endif

  try {
    ///////////////
    // MAJ du PC //
    ///////////////
    tag         = TAG(250);
    pfldMontant = (TCurrencyField*)FieldByName(strfHI_Montant);
    Currency    curNegMontant(-pfldMontant->AsCurrency);
    AnsiString  strNoCpt(FieldByName(strfHI_Compte)->AsString);

    bEstCrediteur = EstCrediteur;
    DateImputation = FieldByName(strfHI_DateImputation)->AsDateTime;
    ptblPC->ChangeSolde(strNoCpt,curNegMontant,bEstCrediteur,DateImputation);

    ///////////////////////////////////////////////////
    // Annulation de l'éventuel lettrage/prélettrage //
    ///////////////////////////////////////////////////
    if( m_bDelLettrage && !EstNonLettre) {
      tag = TAG(251);
      Delettrer(HIAD_DELETTRER_LA_LIGNE_ET_PRELETTRER_LE_RESTE);
    }


    tag    = TAG(252);
    uFlags = (pfldFlags = (TIntegerField*)FieldByName(strfHI_Flags))->AsInteger;
    if(uFlags & HIFLAGS_NORMALE)
    { // Ligne créée par la fonction de base
      ///////////////////////////////////////////////
      // Destruction physique de la ligne courante //
      ///////////////////////////////////////////////
      tag = TAG(253);
      lstcptDeleted.push_back(strNoCpt);
      if (!ptblHI2->IsEmpty())
        ptblHI2->Delete();
      Delete();
      ptblPC->ChangeSolde(strNoCpt,0,bEstCrediteur,DateImputation);

      // Notification du type de la ligne annulée (si la ligne est corrective c'est qu'elle est issue d'une ligne importée)
      bEtaitImportee = (uFlags & HIFLAGS_EST_CORRECTIVE);
    }
    else
    { // Ligne importée
      ///////////////////////////////////////
      // Rectifiction de la ligne courante //
      ///////////////////////////////////////
      CDBRecord      dbr, dbr2;
      TIntegerField* pfldIDEcriture; // Champ "ID Ecriture"
      TIntegerField* pfldFlagLettrage;
      TStringField*  pfldLettrage;
      TFloatField *pfldQuantite;
      double Quantite;

      // => Lecture de la ligne à annuler
      ASSERT(FieldByName(strfHI_IDEcriture)->AsInteger != nIDEcrRectifiee);
      tag = TAG(254);
      dbr << *this;
      EnregitrementDansHI2 = !ptblHI2->IsEmpty();
      if (EnregitrementDansHI2)
        dbr2 << *ptblHI2;
      // => Annulation de la ligne (avec conservation de la marque "Lettrage modifié" pour que la compta
      //    d'origine sache que le lettrage d'origine a été modifié)
      tag = TAG(255);
      pfldIDEcriture   = ( TIntegerField*)FieldByName(strfHI_IDEcriture   );
      pfldFlagLettrage = ( TIntegerField*)FieldByName( strfHI_FlagLettrage);
      pfldLettrage     = (  TStringField*)FieldByName( strfHI_Lettrage    );
      pfldQuantite = (TFloatField *)ptblHI2->FieldByName(strfHI_Quantite);
      Quantite = pfldQuantite->IsNull ? D_NS : pfldQuantite->AsFloat;
      if (!ptblHI2->IsEmpty())
        ptblHI2->Delete();
      Delete();
      //On enlève le filtre car sinon l'AutoId change après le Post() et l'insertion dans revao$2h se fait avec un mauvais AutoId
      Filtered = false;
      Insert();
      *this << dbr;
      pfldFlags->AsInteger      = HIFLAGS_EST_ANNULEE | (uFlags & HIFLAGS_LETTRAGE_EST_MODIFIE);
      pfldIDEcriture->AsInteger = nIDEcrRectifiee;
      pfldFlagLettrage->AsInteger = HIFLAG_LETTRAGE_NON_LETTRE;
      pfldLettrage->Clear();
      FieldByName( strfHI_Reviseur )->Clear();
      FieldByName( strfHI_Reference)->Clear();
      Post();
      if (EnregitrementDansHI2)
      {
        ptblHI2->Insert();
        *ptblHI2 << dbr2;
        ptblHI2->FieldByName(strfHI_AutoID)->AsInteger = FieldByName(strfHI_AutoID)->AsInteger;
        ptblHI2->Post();
      }

      // => Création de la ligne "Annulante" par inversion des montants d'origine et calculé
      tag = TAG(256);
      Insert();
      *this << dbr;
      pfldMontant->AsCurrency   = curNegMontant;
      pfldMontant               = (TCurrencyField*)FieldByName(strfHI_MontantOrigine);
      pfldMontant->AsCurrency   = -pfldMontant->AsCurrency;
      pfldFlags->AsInteger      = HIFLAGS_NORMALE_ANNULEE;
      pfldIDEcriture->AsInteger = nIDEcrRectifiee;
      pfldFlagLettrage->AsInteger = HIFLAG_LETTRAGE_NON_LETTRE;
      pfldLettrage->Clear();
      FieldByName( strfHI_Reviseur )->Clear();
      FieldByName( strfHI_Reference)->Clear();
      Post();
      if (EnregitrementDansHI2)
      {
        ptblHI2->Insert();
        *ptblHI2 << dbr2;
        if (Quantite != D_NS)
        {
          pfldQuantite->AsFloat = -Quantite;
        }
        ptblHI2->FieldByName(strfHI_AutoID)->AsInteger = FieldByName(strfHI_AutoID)->AsInteger;
        ptblHI2->Post();
      }
      // Notification du type de la ligne annulée
      bEtaitImportee = true;
      //On remet le filtre
      Filtered = bFiltered;
    }
  } catch(Exception& e) {
    Filtered = bFiltered;
    throw EUser(tag, e);
  }
 } /* TTableHI::AnnulerLigne() */


 /*----------------------------------------------------------------------------*\
 ------------- TTableHI::TransfererLigne() --------------------------------------
 --------------------------------------------------------------------------------
 -                     L'ENREGISTREMENT COURANT EST MODIFIE                     -
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette procédure permet de transférer la ligne courante dans une autre     -
 - écriture.                                                                    -
 -                                                                              -
 - Paramètres :                                                                 -
 -   nIDEcrDst : ID de l'écriture de destination de la ligne courante.          -
 -                                                                              -
 - Note : Le transfert d'une ligne s'effectue par destruction/recréation pour   -
 -        préserver l'ordre (grâce à l'ID autoincrémenté) d'origine des lignes  -
 -        d'une écriture.                                                       -
 \*----------------------------------------------------------------------------*/
 void __fastcall TTableHI::TransfererLigne(CTable *tblHI2, int nIDEcrDst)
 {
  CDBRecord dbRec, dbRec2;     // L'enregistrement courant
  EICTag    tag;
  bool      bAutoIDOk, bEnregistrementDansHI2;

  // On ne peut transférer ni une ligne d'une nouvelle écriture, ni une ligne d'écriture à l'intérieur de la même écriture, ni une ligne d'écart d'arrondi
  ASSERT((nIDEcrDst != IdEcritureNouvelle) &&
          (FieldByName(strfHI_IDEcriture)->AsInteger != nIDEcrDst) &&
          !(FieldByName(strfHI_Flags)->AsInteger & HIFLAGS_ECART_ARRONDI));

  bool bFiltered = Filtered;

  try {
    ///////////////////////////
    // Transfert de la ligne //
    ///////////////////////////
    // Destruction
    tag = TAG(260);
    bAutoIDOk = ( FieldByName( strfHI_AutoID)->AsInteger==nOldAutoID);
    dbRec << *this;
    bEnregistrementDansHI2 = !tblHI2->IsEmpty();
    if (bEnregistrementDansHI2)
    {
      dbRec2 << *tblHI2;
      tblHI2->Delete();
    }
    Delete();

    // Recréation
    //On enlève le filtre car sinon l'AutoId change après le Post() et l'insertion dans revao$2h se fait avec un mauvais AutoId
    Filtered = false;
    tag = TAG(261);
    Insert();
    *this << dbRec;
    ((TIntegerField*)FieldByName(strfHI_IDEcriture))->AsInteger = nIDEcrDst;
    Post();
    if( bAutoIDOk) nNewAutoID = FieldByName( strfHI_AutoID)->AsInteger;
    if (bEnregistrementDansHI2)
    {
      tblHI2->Insert();
      *tblHI2 << dbRec2;
      tblHI2->FieldByName(strfHI_AutoID)->AsInteger = FieldByName(strfHI_AutoID)->AsInteger;
      tblHI2->Post();
    }
    Filtered = bFiltered;
  } catch(Exception& e) {
    Cancel();
    tblHI2->Cancel();
    Filtered = bFiltered;
    throw EUser(tag, e);
  }
 } /* TTableHI::TransfererLigne() */


 /*----------------------------------------------------------------------------*\
 ------------- TTableHI::AjouterLigneDe() ---------------------------------------
 --------------------------------------------------------------------------------
 -                     L'ENREGISTREMENT COURANT EST MODIFIE                     -
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette procédure permet d'ajouter une ligne d'écriture à partir de         -
 - l'enregistrement courant d'une table HI Temporaire puis de supprimer ce      -
 - dernier.                                                                     -
 -                                                                              -
 - Paramètres :                                                                 -
 -   ptblHITmp      : HI Temporaire duqel importer l'enregistrement courant.    -
 -   cpe            : Propriétés de l'écriture associée à la ligne à ajouter.   -
 -   ptblPC         : PC associé au HI pour la MAJ de soldes                    -
 -   bEstCorrective : TRUE si la ligne à ajouter est une ligne corrective (i.e. -
 -                    une ligne qui corrige une ligne importée).                -
 \*----------------------------------------------------------------------------*/
 void __fastcall TTableHI::AjouterLigneDe(TTableHITmp*          ptblHITmp,
                                          const CPropsEcriture& cpe,
                                          TTablePC*             ptblPC,
                                          CTable*               ptblHI2,
                                          bool                  bEstCorrective,
                                          int                   nReviseur /* = 0 */,
                                          int                   nRef /* = 0 */,
                                          TListLettragesAModifier *lLettragesAModifier/* = NULL*/)
 {
  EICTag tag;
  AnsiString     strLettrage;
  HIFlagLettrage eFlagLettrage;
  bool           bVerifLettrage = false,LettrageN = false;

  ASSERT(ptblHITmp && ptblHITmp->Active && !ptblHITmp->IsEmpty());
  ASSERT(ptblPC && ptblPC->Active && !ptblPC->Filtered);
  ASSERT(ptblHI2 && ptblHI2->Active && !ptblHI2->Filtered);


  try {
    ////////////////////////////////
    // Ajout de la nouvelle ligne //
    ////////////////////////////////
    // => Création d'une nouvelle ligne
    tag = TAG(270); Insert();

    // => MAJ des propriétés de l'écriture
    tag = TAG(271);
    *this << cpe;
    cpe.InitHIPieceFrom(this, ptblHITmp);

    // => Valeurs spécifiques à chaque ligne d'écriture
    tag = TAG(272);
    FieldByName(strfHI_LibelleOperation)->AsString = ptblHITmp->FieldByName(TTableHITmp::strfHITmp_LibelleOperation)->AsString;

    FieldByName( strfHI_ModePaiement)->AsInteger   = ptblHITmp->FieldByName( TTableHITmp::strfHITmp_ModePaiement)->AsInteger;


    if ( ptblHITmp->FieldByName( TTableHITmp::strfHITmp_DateEcheance)->IsNull)
         FieldByName( strfHI_DateEcheance)->Clear();
    else FieldByName( strfHI_DateEcheance)->AsDateTime  = ptblHITmp->FieldByName( TTableHITmp::strfHITmp_DateEcheance)->AsDateTime;

    if(  ptblHITmp->FieldByName( TTableHITmp::strfHITmp_DateEP)->IsNull)
         FieldByName( strfHI_DateEP)->Clear();
    else FieldByName( strfHI_DateEP)->AsDateTime  = ptblHITmp->FieldByName( TTableHITmp::strfHITmp_DateEP)->AsDateTime;
    if(cpe.Flags == HIFLAGS_IMPORTEE)
    { // => Assimilation du lettrage importé
      //    Lorsqu'on ajoute une nouvelle ligne standard au HI, il ne peut pas y avoir de lettrage à mettre à jour
      AnsiString strLettrage(ptblHITmp->FieldByName(TTableHITmp::strfHITmp_Lettrage)->AsString);
      if(!strLettrage.IsEmpty())
      { // Positionnement du lettrage (alpha majuscule obligatoirement)
        FieldByName(strfHI_Lettrage)->AsString      = strLettrage;
        FieldByName(strfHI_FlagLettrage)->AsInteger = HIFLAG_LETTRAGE_LETTRE_IMPORTE;
      }
    }

    FieldByName( strfHI_Reviseur )->AsInteger = nRef==0 ? m_nReviseur            : nReviseur;
    FieldByName( strfHI_Reference)->AsInteger = nRef==0 ? GetReferenceSuivante() : nRef;

    // => Montants
    tag = TAG(273);
    ASSERT(ptblHITmp->FieldByName(TTableHITmp::strfHITmp_Debit)->IsNull ^
            ptblHITmp->FieldByName(TTableHITmp::strfHITmp_Credit)->IsNull);

    TCurrencyField* pfldTmpDebitCredit;
    bool            bIsCrediteur;

    pfldTmpDebitCredit = (TCurrencyField*)ptblHITmp->FieldByName(TTableHITmp::strfHITmp_Debit);
    bIsCrediteur       = pfldTmpDebitCredit->IsNull;
    EstCrediteur       = bIsCrediteur;

    if(bIsCrediteur)
      pfldTmpDebitCredit = (TCurrencyField*)ptblHITmp->FieldByName(TTableHITmp::strfHITmp_Credit);

    Currency curMontant(pfldTmpDebitCredit->AsCurrency);

    // Montant d'origine
    ASSERT(curMontant != 0.0);
    FieldByName(strfHI_MontantOrigine)->AsCurrency = curMontant;

    // Montant converti (dans la devise du dossier)
    FieldByName(strfHI_Montant)->AsCurrency = curMontant = (Currency)DeviseConvToDef(cpe.Devise, curMontant);
    //ASSERT(curMontant != 0.0); Accepter maintenant pour les dossiers tenue en EUR lorsque l'on passe un écriture de 1 centime en FRF

    // => Compte
    tag = TAG(274);

    ASSERT( CEditCompte::CM_CompleteCompte); // Ce membre devrait toujours être initialisé

    AnsiString strCompte = CEditCompte::CM_CompleteCompte(ptblHITmp->FieldByName(TTableHITmp::strfHITmp_Compte)->AsString);
    FieldByName(strfHI_Compte)->AsString = strCompte;

    // => Mise à jour éventuelle du PC (dans la devise du dossier)
    tag = TAG(275);
    if(!ptblPC->EstUnCompteExistant(strCompte))
    { // Création d'un nouveau compte dans le PC (avec intitulé inconnu)
      ptblPC->CreerCompte(CCompte(strCompte.c_str(), NULL));
    }
    ptblPC->ChangeSolde(strCompte,curMontant,bIsCrediteur,cpe.DateImputation);

    // => Type de la ligne
    if(bEstCorrective)
    { // On doit créer une ligne corrective (d'une écriture importée)
      tag = TAG(276);
      FieldByName(strfHI_Flags)->AsInteger = HIFLAGS_EST_NORMALE | HIFLAGS_EST_CORRECTIVE;
    }
    else
    { // La ligne créée est normale (éventuellement à contrepasser) ou importée
      ASSERT((FieldByName(strfHI_Flags)->AsInteger == HIFLAGS_EST_NORMALE)                             ||
              (FieldByName(strfHI_Flags)->AsInteger == (HIFLAGS_EST_NORMALE | HIFLAGS_A_CONTREPASSER)) ||
              (FieldByName(strfHI_Flags)->AsInteger == HIFLAGS_IMPORTEE));
    }

    if( !ptblHITmp->FieldByName( TTableHITmp::strfHITmp_Lettrage)->IsNull && ( cpe.Flags==HIFLAGS_NORMALE)) {
      strLettrage    =                  ptblHITmp->FieldByName( TTableHITmp::strfHITmp_Lettrage    )->AsString;
      eFlagLettrage  = ( HIFlagLettrage)ptblHITmp->FieldByName( TTableHITmp::strfHITmp_FlagLettrage)->AsInteger;
      bVerifLettrage = ( LIGNE_EST_LETTRE( eFlagLettrage) || LIGNE_EST_LETTRE_NP1( eFlagLettrage));
      FieldByName( strfHI_Lettrage    )->AsString  = strLettrage;
      FieldByName( strfHI_FlagLettrage)->AsInteger = ( int)eFlagLettrage;
      switch (eFlagLettrage)
        {
          case HIFLAG_LETTRAGE_LETTRE_IMPORTE:
          case HIFLAG_LETTRAGE_LETTRE_EIC:
            LettrageN = true;
          case HIFLAG_LETTRAGE_LETTRE_IMPORTE_NP1:
          case HIFLAG_LETTRAGE_LETTRE_NP1:
            if (!(LettrageN ^ (cm_DateFinExercice < cpe.DateImputation)))
              if (lLettragesAModifier)
                {
                  LettragesAModifier Lettrage;
                  Lettrage.Compte = strCompte;
                  Lettrage.Lettrage = strLettrage;
                  Lettrage.FlagLettrage = eFlagLettrage;
                  lLettragesAModifier->push_back(Lettrage);
                }
            break;
          default:
            ASSERT(false);
          case HIFLAG_LETTRAGE_PRELETTRE:
          case HIFLAG_LETTRAGE_NON_LETTRE:
            break;
        }
    }

    if ( ptblHITmp->FieldByName( TTableHITmp::strfHITmp_IDImage)->IsNull)
         FieldByName( strfHI_IDImage)->Clear();
    else FieldByName( strfHI_IDImage)->AsInteger = ptblHITmp->FieldByName( TTableHITmp::strfHITmp_IDImage)->AsInteger;
    if (ptblHITmp->FieldByName( TTableHITmp::strfHITmp_IDImageModifie)->AsBoolean)
      FieldByName(strfHI_Flags)->AsInteger = FieldByName(strfHI_Flags)->AsInteger | HIFLAGS_IMAGE_MODIFIEE;

    // => Validation de l'ajout
    tag = TAG(277); Post();
    TDateTimeField *fTmpDatePeriode = NULL, *fHI2DatePeriode = NULL;
    int AutoID = FieldByName(strfHI_AutoID)->AsInteger;
    ptblHI2->SetKey();
    ptblHI2->FieldByName(strfHI_AutoID)->AsInteger = AutoID;
    if (ptblHI2->GotoKey())
      ptblHI2->Edit();
    else
      ptblHI2->Insert();
    *ptblHI2 << cpe;
    ptblHI2->FieldByName(strfHI_PieceExterne)->AsString     = ptblHITmp->FieldByName(TTableHITmp::strfHITmp_PieceExterne)->AsString;
    ptblHI2->FieldByName(strfHI_RAOData)->AsString          = ptblHITmp->FieldByName(TTableHITmp::strfHITmp_RAOData)->AsString;
    fTmpDatePeriode = (TDateTimeField*)ptblHITmp->FindField( TTableHITmp::strfHITmp_DateDebPeriode);
    fHI2DatePeriode = (TDateTimeField*)ptblHI2->FindField( strfHI_DateDebPeriode);
    if ( fTmpDatePeriode && fHI2DatePeriode) {
      if ( fTmpDatePeriode->IsNull)
           fHI2DatePeriode->Clear();
      else fHI2DatePeriode->AsDateTime  = fTmpDatePeriode->AsDateTime;
    }
    fTmpDatePeriode = (TDateTimeField*)ptblHITmp->FindField( TTableHITmp::strfHITmp_DateFinPeriode);
    fHI2DatePeriode = (TDateTimeField*)ptblHI2->FindField( strfHI_DateFinPeriode);
    if ( fTmpDatePeriode && fHI2DatePeriode) {
      if ( fTmpDatePeriode->IsNull)
           fHI2DatePeriode->Clear();
      else fHI2DatePeriode->AsDateTime  = fTmpDatePeriode->AsDateTime;
    }
    ptblHI2->FieldByName( strfHI_Designation )->AsString    = ptblHITmp->FieldByName( TTableHITmp::strfHITmp_Designation )->AsString;
    ptblHI2->FieldByName( strfHI_CodeTVA     )->AsString    = ptblHITmp->FieldByName( TTableHITmp::strfHITmp_CodeTVA     )->AsString;
    ptblHI2->FieldByName( strfHI_Banque      )->AsString    = ptblHITmp->FieldByName( TTableHITmp::strfHITmp_Banque      )->AsString;
    ptblHI2->FieldByName( strfHI_CodeAnalytik)->AsString    = ptblHITmp->FieldByName( TTableHITmp::strfHITmp_CodeAnalytik)->AsString;
    ptblHI2->FieldByName(strfHI_AutoID)->AsInteger = AutoID;
    if ( ptblHITmp->FieldByName( TTableHITmp::strfHITmp_TauxTVA)->IsNull)
         ptblHI2->FieldByName( strfHI_TauxTVA     )->Clear();
    else ptblHI2->FieldByName( strfHI_TauxTVA     )->AsFloat     = ptblHITmp->FieldByName( TTableHITmp::strfHITmp_TauxTVA)->AsFloat;
    if ( ptblHITmp->FieldByName( TTableHITmp::strfHITmp_Quantite)->IsNull)
         ptblHI2->FieldByName( strfHI_Quantite    )->Clear();
    else ptblHI2->FieldByName( strfHI_Quantite    )->AsFloat     = ptblHITmp->FieldByName( TTableHITmp::strfHITmp_Quantite)->AsFloat;
    ptblHI2->Post();

    if( ptblHITmp->FieldByName( TTableHITmp::strfHITmp_IDLigne)->AsInteger==nOldAutoID)
        nNewAutoID = FieldByName( strfHI_AutoID)->AsInteger;

    if( bVerifLettrage) {
      TDateTimeField *pfldDate;
      Currency        curSolde;
      bool            bFaireLet = true;
      bool            bNOnly    = true;
      TTableHI       *ptblHI    = CreerTableLettrage( NULL, NULL, NULL, &pfldDate);
      TBooleanField  *pfldEstCrediteur = (  TBooleanField*)ptblHI->FieldByName( strfHI_EstCrediteur);
      TCurrencyField *pfldMontant      = ( TCurrencyField*)ptblHI->FieldByName( strfHI_Montant     );
      ptblHI->FiltrerLettrageRange( strCompte, strLettrage, eFlagLettrage);
      // Calcule le solde du lettrage et regarde si c'est un lettrage N+1
      for( ptblHI->First(); !ptblHI->Eof; ptblHI->Next()) {
        bNOnly &= ( pfldDate->AsDateTime<=cm_DateFinExercice);
        if( pfldEstCrediteur->AsBoolean) curSolde = curSolde -  pfldMontant->AsCurrency;
                                    else curSolde = curSolde +  pfldMontant->AsCurrency;
      }
      // Si le lettrage n'est pas équilibré, on le remplace par un prélettrage
      if(( curSolde!=0) && ( LIGNE_EST_LETTRE( eFlagLettrage) || LIGNE_EST_LETTRE_NP1( eFlagLettrage))) {
        strLettrage = PrelettrageSuivant( strCompte);
        bFaireLet   = false;
      }
      // Modification ....
      if( !bFaireLet) {
        int nSaveRecordCount;
        for( ptblHI->First(); !ptblHI->Eof && ptblHI->RecordCount; ) {
          nSaveRecordCount = ptblHI->RecordCount;
          ptblHI->Edit();
          if( bFaireLet) ptblHI->Lettrer( strLettrage, !bNOnly);
                    else ptblHI->Prelettrer( strLettrage);
          ptblHI->Post();
          if( nSaveRecordCount==ptblHI->RecordCount) ptblHI->Next(); else ptblHI->First();
        }
      }
             ptblHI->Close();
      delete ptblHI;
    }
  } catch(Exception& e) {
    Cancel();
    ptblHI2->Cancel();
    throw EUser(tag, e);
  }

  // Cette ligne d'écriture a bien été ajoutée
  ptblHITmp->Delete();
 } /* TTableHI::AjouterLigneDe() */


 /*----------------------------------------------------------------------------*\
 ------------- TTableHI::AjouterEcartsChange() ----------------------------------
 --------------------------------------------------------------------------------
 -                     L'ENREGISTREMENT COURANT EST MODIFIE                     -
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette procédure permet d'ajouter des lignes d'écarts de change dans une   -
 - écriture.                                                                    -
 -                                                                              -
 - Paramètres :                                                                 -
 -   cpe       : Propriétés de l'écriture associée à la ligne à ajouter.        -
 -   ptblPC   : PC associé à cet historique.                                    -
 -   pEcartCh : Liste des lignes d'écart de change.                             -
 \*----------------------------------------------------------------------------*/
void __fastcall TTableHI::AjouterEcartsChange( const CPropsEcriture    &cpe,
                                               TTablePC                *ptblPC,
                                               CTable                  *ptblHI2,
                                               const TEcartChgEcriture *pEcartCh)
{
  ASSERT( (State==dsBrowse) && ptblPC && ptblPC->Active);
  ASSERT( (pEcartCh->Count & 1)==0);  // Toujours par deux
  ASSERT( (DeviseCodeDefaut==DeviseCodeFranc) || (DeviseCodeDefaut==DeviseCodeEuro));

  EICTag             nTag;
  TLigneEcartChange *pCurrLigne;

  try {
                      // Parcours toutes les lignes d'écart de change
                      for( int i=0; i<pEcartCh->Count; i++) {
    nTag = TAG( 600);   pCurrLigne = pEcartCh->Items[ i];
    nTag = TAG( 602);   Insert();
    nTag = TAG( 604);   // Copie des propriétés de l'écriture
                        *this << cpe;
                        cpe.InitHIPieceFrom(this, NULL);
                        // Libelle de l'opération
    nTag = TAG( 606);   FieldByName( strfHI_LibelleOperation)->AsString = pCurrLigne->strLibelle;
                        // Montant de la ligne origine et tenue
    nTag = TAG( 608);   FieldByName( strfHI_MontantOrigine)->AsCurrency = pCurrLigne->curMontant;
                        FieldByName( strfHI_Montant       )->AsCurrency = pCurrLigne->curMontant;
                        FieldByName( strfHI_CodeDevise    )->AsInteger  = DeviseCodeDefaut;
                        FieldByName( strfHI_Reviseur      )->AsInteger  = pCurrLigne->nReference==0 ? m_nReviseur            : pCurrLigne->nReviseur;
                        FieldByName( strfHI_Reference     )->AsInteger  = pCurrLigne->nReference==0 ? GetReferenceSuivante() : pCurrLigne->nReference;
                        if ( DeviseCodeDefaut==DeviseCodeFranc) FieldByName( strfHI_TauxChange)->Clear();
                                                           else FieldByName( strfHI_TauxChange)->AsFloat = 1.0;
                        EstCrediteur = pCurrLigne->bIsCrediteur;
                        // Numéro de compte et incrémentation du solde du PC
    nTag = TAG( 610);   FieldByName( strfHI_Compte)->AsString = pCurrLigne->Compte.Compte;
                        ptblPC->ChangeSolde( pCurrLigne->Compte.Compte, pCurrLigne->curMontant, pCurrLigne->bIsCrediteur, cpe.DateImputation);
                        // Modification du flag de la ligne d'écriture
    nTag = TAG( 612);   ASSERT( cpe.Flags==HIFLAGS_EST_NORMALE);
                        FieldByName( strfHI_Flags)->AsInteger = HIFLAGS_EST_NORMALE | HIFLAGS_ECART_CHANGE;
                        // Et hop, il ne reste plus qu'à valider
    nTag = TAG( 614);   Post();
                        ptblHI2->Insert();
                        *ptblHI2 << cpe;
                        ptblHI2->FieldByName(strfHI_AutoID)->AsInteger = FieldByName(strfHI_AutoID)->AsInteger;
                        ptblHI2->Post();
                      }

  } catch ( Exception &e) {
    Cancel();
    ptblHI2->Cancel();
    throw EUser( nTag, e);
  }
}

 /*----------------------------------------------------------------------------*\
 ------------- TTableHI::AjouterEcartArrondi() ----------------------------------
 --------------------------------------------------------------------------------
 -                     L'ENREGISTREMENT COURANT EST MODIFIE                     -
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette procédure permet d'ajouter une ligne d'écart d'arrondi dans une     -
 - écriture.                                                                    -
 -                                                                              -
 - Paramètres :                                                                 -
 -   cpe         : Propriétés de l'écriture associée à la ligne à ajouter.      -
 -   ptblPC      : PC associé à cet historique.                                 -
 -   curEcartArr : Valeur de l'écart d'arrondi (< 0 : Débit; > 0 : Crédit).    -
 \*----------------------------------------------------------------------------*/
 void __fastcall TTableHI::AjouterEcartArrondi(const CPropsEcriture& cpe,
                                               TTablePC*             ptblPC,
                                               CTable               *ptblHI2,
                                               const Currency&       curEcartArr)
 {
  TFloatField* pfldTauxChange; // Champ "taux de change"
  bool         bIsCredit;      // TRUE si l'écart d'arrondi doit être passé au crédit (i.e. > 0)
  EICTag       tag;

  ASSERT((State == dsBrowse) && ptblPC && ptblPC->Active && (curEcartArr != (int)0));
  ASSERT(cpe.CodeDevise != DeviseCodeDefaut);


  try {
    ////////////////////////////////////////////////////////////////
    // Création des comptes d'écart d'arrondis dans le PC associé //
    ////////////////////////////////////////////////////////////////
    ptblPC->CreerComptesArrondis();


    ////////////////////////////////////////////////
    // Ajout de l'écart de change dans l'écriture //
    ////////////////////////////////////////////////
    // => Création d'une nouvelle ligne
    Insert();

    // => MAJ des propriétés de l'écriture (dans la devise du dossier)
    *this << cpe;
    cpe.InitHIPieceFrom(this, NULL);

    // => Valeurs spécifiques à un écart d'arrondi (pas de PièceLiée, RAODAta, Lettrage)
    tag = TAG(280);
    const CDevise& dev(cpe.Devise); // Artifice pour ne pas générer un "Internal error" lors de la compil...
    FieldByName(strfHI_LibelleOperation)->AsString = EICFormat("Ecart d'arrondi %s-> %s", dev.CodeISO.c_str(), DeviseDefaut->CodeISO.c_str());

    // => Montants et compte
    tag = TAG(281);
    bIsCredit = (curEcartArr > (int)0);
    Currency   curMontant(    bIsCredit ? curEcartArr              : -curEcartArr);
    AnsiString strCptEcartArr(bIsCredit ? ptblPC->CptProfiArrondis : ptblPC->CptPerteArrondis);

    ASSERT(ptblPC->EstUnCompteExistant(strCptEcartArr));

    // => Montants (tjs en devise du dossier)
    FieldByName(strfHI_MontantOrigine)->AsCurrency = curMontant;
    FieldByName(strfHI_Montant)->AsCurrency = curMontant;
    EstCrediteur                                    = bIsCredit;
    // => Devise (On écrase les valeurs initialisées par *this << cpe)
    FieldByName(strfHI_CodeDevise)->AsInteger = DeviseCodeDefaut;
    pfldTauxChange = (TFloatField*)FieldByName(TTableHI::strfHI_TauxChange);
    if(DeviseCodeDefaut == DeviseCodeFranc)
    {
      pfldTauxChange->Clear();
    }
    else
    {
      ASSERT(DeviseCodeDefaut == DeviseCodeEuro);
      pfldTauxChange->AsFloat = 1.0;
    }

    FieldByName( strfHI_Reviseur )->AsInteger = m_nReviseur;
    FieldByName( strfHI_Reference)->AsInteger = GetReferenceSuivante();

    // => Compte (avec MAJ du PC dans la devise du dossier)
    tag = TAG(282);
    FieldByName(strfHI_Compte)->AsString = strCptEcartArr;
    ptblPC->ChangeSolde(strCptEcartArr,curMontant,bIsCredit,cpe.DateImputation);

    // => Type de la ligne (on ne génère pas d'écart d'arrondi sur une écriture importée - car elle
    //    est implicitement en monnaie de tenue et pas non plus sur une écriture à contrepasser car elle
    //    telle écriture ne peut être passée que par un assistant qui par définition génére des écritures
    //    en monnaie de tenue).
    ASSERT(cpe.Flags == HIFLAGS_EST_NORMALE);
    tag = TAG(283);
    FieldByName(strfHI_Flags)->AsInteger = HIFLAGS_EST_NORMALE | HIFLAGS_ECART_ARRONDI;

    // => Validation de l'ajout
    Post();
    ptblHI2->Insert();
    *ptblHI2 << cpe;
    ptblHI2->FieldByName(strfHI_AutoID)->AsInteger = FieldByName(strfHI_AutoID)->AsInteger;
    ptblHI2->Post();
  } catch(Exception& e) {
    Cancel();
    ptblHI2->Cancel();
    throw EUser(tag, e);
  }
 } /* TTableHI::AjouterEcartArrondi() */



 /*----------------------------------------------------------------------------*\
 ------------- TTableHI::RectifierEcriture() ------------------------------------
 --------------------------------------------------------------------------------
 -                     L'ENREGISTREMENT COURANT EST MODIFIE                     -
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette procédure permet de rectifier une écriture i.e. d'en générer une    -
 - nouvelle en prenant en compte les éventuels ajout, supressions et            -
 - modifications à opérer.                                                      -
 -                                                                              -
 - Paramètres :                                                                 -
 -   nIDEcrOrigine : ID de l'écriture d'origine (IdEcritureNouvelle si l'on     -
 -                   souhaite créer une nouvelle écriture ou bien ID de         -
 -                   l'écriture d'origine à rectifier avec ptblHITmp)           -
 -   cprRectifiee  : Propriétés de l'écriture rectifiée (celle à générer)       -
 -   ptblHITmp     : Nouvelle écriture (celle d'origine qui a subit des         -
 -                   éventuels ajouts, suppressions ou modifications).          -
 -   ptblPC        : PC associé au HI pour la MAJ de soldes                     -
 -   pbarre        : Barre de progression à utiliser (NULL pour aucune).        -
 \*----------------------------------------------------------------------------*/
 void __fastcall TTableHI::RectifierEcriture(int                   nIDEcrOrigine,
                                              const CPropsEcriture& cpeRectifiee,
                                              TTableHITmp*          ptblHITmp,
                                              TTablePC*             ptblPC,
                                              CTable*               ptblHI2,
                                              CBarre*               pbarre)
 {
  TListComptes    lstcptDeleted;   // Liste de comptes dont au moins un mouvement a été détruit physiquement

  TAutoIncField*  pfldAutoIDOrigine;
  TStringField*   pfldCompte;
  TStringField*   pfldLibelle;
  TStringField*   pfldPiece;
  TStringField*   pfldPieceExterne;
  TCurrencyField* pfldMontantO;
  TIntegerField*  pfldFlags;
  TStringField*   pfldDesignation;
  TStringField*   pfldCodeTVA;
  TStringField*   pfldBanque;
  TIntegerField*  pfldModePaiement;
  TIntegerField*  pfldReviseur;
  TIntegerField*  pfldReference;
  TFloatField*    pfldTauxTVA;
  TFloatField*    pfldQuantite;
  TDateTimeField* pfldDateEcheance;
  TDateTimeField* pfldDateEP;
  TStringField*   pfldCodeAnalytik;
  TStringField*   pfldLettrage;
  TIntegerField*  pfldFlagLettrage;
  TIntegerField*  pfldIDImage;
  TDateTimeField* pfldDateDebPeriode;
  TDateTimeField* pfldDateFinPeriode;

  TIntegerField*  pfldTmpID;
  TStringField*   pfldTmpCompte;
  TStringField*   pfldTmpLibelle;
  TStringField*   pfldTmpPiece;
  TStringField*   pfldTmpPieceExterne;
  TCurrencyField* pfldTmpDebit;
  TCurrencyField* pfldTmpCredit;
  TBooleanField*  pfldTmpNouvLigne;
  TStringField*   pfldTmpDesignation;
  TStringField*   pfldTmpCodeTVA;
  TStringField*   pfldTmpBanque;
  TStringField*   pfldTmpLettrage;
  TIntegerField*  pfldTmpModePaiement;
  TFloatField*    pfldTmpTauxTVA;
  TFloatField*    pfldTmpQuantite;
  TDateTimeField* pfldTmpDateEcheance;
  TDateTimeField* pfldTmpDateEP;
  TStringField*   pfldTmpCodeAnalytik;
  TIntegerField*  pfldTmpIDImage;
  TDateTimeField* pfldTmpDateDebPeriode;
  TDateTimeField* pfldTmpDateFinPeriode;

  bool       bCrediteur;
  EICTag     tag;
  bool       bEtaitImportee;                 // TRUE si une ligne annulée était importée à l'origine
  AnsiString strOldIndex( IndexName);        // Index actif avant validation
  TVarRec    vrIDEcrOrigine( nIDEcrOrigine); // ID de l'écriture à rectifier
  bool       bTmp;

  ASSERT(Active && !Filtered);
  ASSERT(ptblPC && ptblPC->Active && !ptblPC->Filtered);
  ASSERT(ptblHITmp && ptblHITmp->Active);
  ASSERT((nIDEcrOrigine != IdEcritureNouvelle) || !ptblHITmp->IsEmpty()); // Une écriture entièrement nouvelle ne peut pas être vide


  try {
    tag               = TAG(290);
    pfldAutoIDOrigine = (TAutoIncField*)FieldByName(strfHI_AutoID);
    pfldCompte        = (TStringField*)FieldByName(strfHI_Compte);
    pfldLibelle       = (TStringField*)FieldByName(strfHI_LibelleOperation);
    pfldPiece         = (TStringField*)FieldByName(strfHI_Piece);
    pfldPieceExterne  = (TStringField*)ptblHI2->FieldByName(strfHI_PieceExterne);
    pfldMontantO      = (TCurrencyField*)FieldByName(strfHI_MontantOrigine);
    pfldFlags         = (TIntegerField*)FieldByName(strfHI_Flags);

    pfldDesignation    = (   TStringField*)ptblHI2->FieldByName( strfHI_Designation );
    pfldCodeTVA        = (   TStringField*)ptblHI2->FieldByName( strfHI_CodeTVA     );
    pfldBanque         = (   TStringField*)ptblHI2->FieldByName( strfHI_Banque      );
    pfldModePaiement   = (  TIntegerField*)FieldByName( strfHI_ModePaiement);
    pfldReviseur       = (  TIntegerField*)FieldByName( strfHI_Reviseur    );
    pfldReference      = (  TIntegerField*)FieldByName( strfHI_Reference   );
    pfldTauxTVA        = (    TFloatField*)ptblHI2->FieldByName( strfHI_TauxTVA     );
    pfldQuantite       = (    TFloatField*)ptblHI2->FieldByName( strfHI_Quantite    );
    pfldDateEcheance   = ( TDateTimeField*)FieldByName( strfHI_DateEcheance);
    pfldCodeAnalytik   = (   TStringField*)ptblHI2->FieldByName( strfHI_CodeAnalytik);
    pfldDateEP         = ( TDateTimeField*)FieldByName( strfHI_DateEP      );
    pfldLettrage       = (   TStringField*)FieldByName( strfHI_Lettrage    );
    pfldFlagLettrage   = (  TIntegerField*)FieldByName( strfHI_FlagLettrage);
    pfldIDImage        = (  TIntegerField*)FieldByName( strfHI_IDImage);
    pfldDateDebPeriode = ( TDateTimeField*)ptblHI2->FindField( strfHI_DateDebPeriode);
    pfldDateFinPeriode = ( TDateTimeField*)ptblHI2->FindField( strfHI_DateFinPeriode);

    pfldTmpID           = (TIntegerField*)ptblHITmp->FieldByName(TTableHITmp::strfHITmp_IDLigne);
    pfldTmpCompte       = (TStringField*)ptblHITmp->FieldByName(TTableHITmp::strfHITmp_Compte);
    pfldTmpLibelle      = (TStringField*)ptblHITmp->FieldByName(TTableHITmp::strfHITmp_LibelleOperation);
    pfldTmpPiece        = (TStringField*)ptblHITmp->FieldByName(TTableHITmp::strfHITmp_Piece);
    pfldTmpPieceExterne = (TStringField*)ptblHITmp->FieldByName(TTableHITmp::strfHITmp_PieceExterne);
    pfldTmpDebit      = (TCurrencyField*)ptblHITmp->FieldByName(TTableHITmp::strfHITmp_Debit);
    pfldTmpCredit     = (TCurrencyField*)ptblHITmp->FieldByName(TTableHITmp::strfHITmp_Credit);
    pfldTmpNouvLigne  = (TBooleanField*)ptblHITmp->FieldByName(TTableHITmp::strfHITmp_EstNouvelleLigne);
    pfldTmpLettrage   = (TStringField*)ptblHITmp->FieldByName(TTableHITmp::strfHITmp_Lettrage);
    pfldTmpIDImage    = (TIntegerField*)ptblHITmp->FieldByName(TTableHITmp::strfHITmp_IDImage);

    pfldTmpDesignation    = (   TStringField*)ptblHITmp->FieldByName( TTableHITmp::strfHITmp_Designation );
    pfldTmpCodeTVA        = (   TStringField*)ptblHITmp->FieldByName( TTableHITmp::strfHITmp_CodeTVA     );
    pfldTmpBanque         = (   TStringField*)ptblHITmp->FieldByName( TTableHITmp::strfHITmp_Banque      );
    pfldTmpModePaiement   = (  TIntegerField*)ptblHITmp->FieldByName( TTableHITmp::strfHITmp_ModePaiement);
    pfldTmpTauxTVA        = (    TFloatField*)ptblHITmp->FieldByName( TTableHITmp::strfHITmp_TauxTVA     );
    pfldTmpQuantite       = (    TFloatField*)ptblHITmp->FieldByName( TTableHITmp::strfHITmp_Quantite    );
    pfldTmpDateEcheance   = ( TDateTimeField*)ptblHITmp->FieldByName( TTableHITmp::strfHITmp_DateEcheance);
    pfldTmpCodeAnalytik   = (   TStringField*)ptblHITmp->FieldByName( TTableHITmp::strfHITmp_CodeAnalytik);
    pfldTmpDateEP         = ( TDateTimeField*)ptblHITmp->FieldByName( TTableHITmp::strfHITmp_DateEP      );
    pfldTmpDateDebPeriode = ( TDateTimeField*)ptblHITmp->FindField(   TTableHITmp::strfHITmp_DateDebPeriode);
    pfldTmpDateFinPeriode = ( TDateTimeField*)ptblHITmp->FindField(   TTableHITmp::strfHITmp_DateFinPeriode);

    ///////////////////////////////////////
    // Pose de l'index sur les écritures //
    ///////////////////////////////////////
    tag = TAG( 291);
    IndexName = striHI_IDEcritures;
    ASSERT( ( nIDEcrOrigine != IdEcritureNouvelle) || !FindKey( &vrIDEcrOrigine, 0)); // Une écriture d'origine ne peut pas avoir "IdEcritureNouvelle" comme ID


    ////////////////////////////////////////////////////////////////////
    // Recherche de la ligne qui sera la 1ère de l'écriture rectifiée //
    ////////////////////////////////////////////////////////////////////
    tag = TAG( 292);
    ptblHITmp->First();


    /////////////////////////////////
    // Rectification de l'écriture //
    /////////////////////////////////
    while( FindKey( &vrIDEcrOrigine, 0)) // Note: FindKey se place toujours sur le 1er enregistrement du groupe de lignes qui correspondent à la valeur de clé recherchée
    { // Traitement de la ligne d'origine
      ASSERT( !pfldFlags->IsNull);
      if( pfldFlags->AsInteger & HIFLAGS_EST_ANNULEE)
      { // Cette ligne d'origine est importée_annulée...
        int eAction;  // Action à effectuer pour rectifier cette ligne annulée

        if( MoveBy( 2) == 2)
        {
          if( pfldFlags->AsInteger & HIFLAGS_EST_CORRECTIVE)
          { // ...et une ligne corrective lui correspond...
            if( ptblHITmp->ContientLaLigneDOrigine( pfldAutoIDOrigine->AsInteger, bTmp))
            { // ...et cette ligne corrective doit figurer dans l'écriture rectifiée...
              if( bTmp)
              { // ...à la position courante
                // => On va donc transférer la ligne annulée et son annulante puis sa corrective (éventuellement modifiée)
                eAction = 2;
              }
              else
              { // ...mais d'autres (nouvelles) lignes ont été insérées avant cette ligne d'origine
                // => On va d'abord insérer les nouvelles lignes
                if( !pfldTmpNouvLigne->AsBoolean)
                { // Erreur: Pb dans le HITmp: L'ordre des lignes d'origine est incorrect
                  EICThrowInvalidArgument( TAG( 293));
                }
                goto LigneNouvelle;
              }
            }
            else
            { // ...mais cette ligne corrective doit être détruite
              // => On va donc transférer la ligne annulée et son annulante correspondante puis détruire sa corrective
              eAction = 1;
            }
          }
          else
          { // ...mais elle n'a pas de ligne corrective associée (elle a donc été supprimée via la fct de base)
            // => On va donc la transférer (avec sa ligne annulante associée) dans l'écriture rectifiée
            eAction = 0;
          }
        }
        else
        { // ...et n'a pas de ligne corrective associée (elle a donc été supprimée via la fct de base) et on est à la fin de l'écriture d'origine
          // => On va donc la transférer (avec sa ligne annulante associée) dans l'écriture rectifiée
          eAction = 0;
        }

        // On se replace sur la ligne d'origine (importée_annulée)...
        // ...et on la transfère dans l'écriture rectifiée...
        tag = TAG( 294);
        VERIFY( FindKey( &vrIDEcrOrigine, 0));
        TransfererLigne(ptblHI2, cpeRectifiee.IDEcriture);

        // ...avec sa ligne annulante associée
        tag = TAG( 295);
        VERIFY( FindKey( &vrIDEcrOrigine, 0));
        if( pfldFlags->AsInteger != HIFLAGS_NORMALE_ANNULEE)
        { // Erreur: Pb dans le HI: Une ligne annulée n'a pas de ligne annulante correspondante
          EICThrowInvalidArgument( TAG( 296));
        }
        TransfererLigne(ptblHI2, cpeRectifiee.IDEcriture);

        switch( eAction)
        { // ...et sa ligne corrective éventuellement modifiée
          case 2 :
            VERIFY( FindKey( &vrIDEcrOrigine, 0));
            if( !( pfldFlags->AsInteger & HIFLAGS_EST_CORRECTIVE))
            { // Erreur: Pb dans le HI: Ligne corrective non trouvée
              EICThrowInvalidArgument( TAG( 297));
            }
            goto LigneDOrigine;

          // ...et on détruit sa ligne corrective...
          case 1 :
            VERIFY( FindKey( &vrIDEcrOrigine, 0));
            if( !( pfldFlags->AsInteger & HIFLAGS_EST_CORRECTIVE))
            { // Erreur: Pb dans le HI: Ligne corrective non trouvée
              EICThrowInvalidArgument( TAG( 298));
            }
            AnnulerLigne( ptblPC,ptblHI2, cpeRectifiee.IDEcriture, bEtaitImportee, lstcptDeleted);

          // ...et on continue la rectification
          default:
            continue;
        }
      }

      if(ptblHITmp->Eof)
      { // Il n'y a plus de nouvelle ligne à générer
        // => On annule la ligne d'origine qui existe à tort (qui ne doit plus figurer dans la nouvelle écriture)
        tag = TAG(299);
        AnnulerLigne(ptblPC,ptblHI2, cpeRectifiee.IDEcriture, bEtaitImportee, lstcptDeleted);
        continue;
      }

      ASSERT(!pfldTmpID->IsNull);

      if(pfldTmpNouvLigne->AsBoolean)
      { // Il faut générer une nouvelle ligne dans l'écriture rectifiée...
        LigneNouvelle:

        // L'écriture d'origine peut maintenant accepter une nouvelle ligne avant l'éventuelle suivante
        // => Ajout de cette nouvelle ligne dans l'écriture rectifiée
        ASSERT(pfldTmpID->AsInteger == 0); // Toute nouvelle ligne a un ID à zéro

        tag = TAG(301);
        AjouterLigneDe(ptblHITmp, cpeRectifiee, ptblPC,ptblHI2, false);

        if(pbarre)
          (*pbarre)++;
        continue;
      }

      // La nouvelle ligne est issue de l'écriture d'origine...
      LigneDOrigine:
      ASSERT(pfldTmpID->AsInteger != 0); // Toute ligne issue de l'écriture d'origine indique dans son ID l'autoID d'origine
      ASSERT(!pfldAutoIDOrigine->IsNull);
      ASSERT(pfldAutoIDOrigine->AsInteger <= pfldTmpID->AsInteger);

      if(pfldAutoIDOrigine->AsInteger == pfldTmpID->AsInteger)
      { // ...mais a-t-elle été modifiée dans l'écriture nouvelle ?
        bCrediteur = EstCrediteur;
        if(( pfldMontantO->AsCurrency != (bCrediteur ? pfldTmpCredit : pfldTmpDebit)->AsCurrency) ||
           ( pfldCompte->AsString     != pfldTmpCompte->AsString)                                  ||
           ( pfldLibelle->AsString    != pfldTmpLibelle->AsString)                                 ||
           ( pfldPiece->AsString      != pfldTmpPiece->AsString)                                   ||
           ( pfldDesignation->AsString!= pfldTmpDesignation->AsString) ||
           ( pfldCodeTVA->AsString    != pfldTmpCodeTVA->AsString) ||
           ( pfldBanque->AsString     != pfldTmpBanque->AsString) ||
           ( pfldModePaiement->AsInteger != pfldTmpModePaiement->AsInteger) ||
           ( pfldTauxTVA->AsFloat        != pfldTmpTauxTVA->AsFloat) ||
           ( pfldQuantite->AsFloat       != pfldTmpQuantite->AsFloat) ||
           ( pfldDateEcheance->AsDateTime!= pfldTmpDateEcheance->AsDateTime) ||
           ( pfldDateEP->AsDateTime      != pfldTmpDateEP->AsDateTime) ||
           ( pfldPieceExterne->AsString !=  pfldTmpPieceExterne->AsString) ||
           ( pfldCodeAnalytik->AsString != pfldTmpCodeAnalytik->AsString) ||
           ( pfldDateDebPeriode && pfldTmpDateDebPeriode && (pfldDateDebPeriode->AsDateTime != pfldTmpDateDebPeriode->AsDateTime)) ||
           ( pfldDateFinPeriode && pfldTmpDateFinPeriode && (pfldDateFinPeriode->AsDateTime != pfldTmpDateFinPeriode->AsDateTime))
          )
        {
          int nReviseur   = pfldReviseur->AsInteger;
          int nReference  = pfldReference->AsInteger;
          m_bDelLettrage  = pfldCompte->AsString != pfldTmpCompte->AsString;

          if( m_bDelLettrage) { ptblHITmp->Edit(); pfldTmpLettrage->Clear(); ptblHITmp->Post(); }

          // La ligne d'origine doit être modifiée
          // => Annulation de la ligne d'origine
          tag = TAG(302);
          AnnulerLigne(ptblPC,ptblHI2, cpeRectifiee.IDEcriture, bEtaitImportee, lstcptDeleted);
          m_bDelLettrage = false;

          // => Ajout de la ligne modifiée dans l'écriture rectifiée
          tag = TAG(303);
          AjouterLigneDe(ptblHITmp, cpeRectifiee, ptblPC,ptblHI2, bEtaitImportee, nReviseur, nReference);
        }
        else if (pfldIDImage->AsInteger != pfldTmpIDImage->AsInteger)
        {
          //Seule l'IDImage a été modifiée, on fait la modif sans créer d'annulée/annulante
          Edit();
          if ( pfldTmpIDImage->IsNull)
            pfldIDImage->Clear();
          else
            pfldIDImage->AsInteger = pfldTmpIDImage->AsInteger;
          pfldFlags->AsInteger = pfldFlags->AsInteger | HIFLAGS_IMAGE_MODIFIEE;
          Post();
        }
        else
        { // La ligne d'origine n'a pas été modifiée
          // => Destruction de la nouvelle ligne mais transfert de la ligne d'origine dans l'écriture rectifiée
          tag = TAG(304);
          ptblHITmp->Delete();

          tag = TAG(305); ASSERT(FieldByName(strfHI_CodeDevise)->AsInteger == cpeRectifiee.CodeDevise);
          TransfererLigne(ptblHI2,cpeRectifiee.IDEcriture);
        }
        if(pbarre)
          (*pbarre)++;
        continue;
      }
      else
      { // ...mais une/des ligne(s) d'origine a/ont été détruite(s) dans la nouvelle écriture
        // => On annule la ligne d'origine qui ne doit plus figurer dans l'écriture rectifiée
        tag = TAG(306);
        AnnulerLigne(ptblPC,ptblHI2, cpeRectifiee.IDEcriture, bEtaitImportee, lstcptDeleted);
        continue;
      }
    }
    ASSERT( !FindKey( &vrIDEcrOrigine, 0)); // Ecriture d'origine entièrement traitée


    ///////////////////////////////////////////////////////////////
    // Ajout des nouvelles lignes en fin de l'écriture rectifiée //
    ///////////////////////////////////////////////////////////////
    tag = TAG(307);
    TListLettragesAModifier lLettragesAModifier;
    while(!ptblHITmp->IsEmpty())
    {
      AjouterLigneDe(ptblHITmp, cpeRectifiee, ptblPC,ptblHI2, false,0,0,&lLettragesAModifier);
      if(pbarre)
        (*pbarre)++;
    }
    if (lLettragesAModifier.size())
      {
        IndexName = sziHI_LettrageDate;
        while (lLettragesAModifier.size())
          {//On a des lettrages à reclasser (N ou N+1)
            SetRangeStart();
            KeyFieldCount = 3;
            pfldCompte->AsString = lLettragesAModifier.back().Compte;
            pfldLettrage->AsString = lLettragesAModifier.back().Lettrage;
            pfldFlagLettrage->AsInteger = lLettragesAModifier.back().FlagLettrage;
            SetRangeEnd();
            KeyFieldCount = 3;
            pfldCompte->AsString = lLettragesAModifier.back().Compte;
            pfldLettrage->AsString = lLettragesAModifier.back().Lettrage;
            pfldFlagLettrage->AsInteger = lLettragesAModifier.back().FlagLettrage;
            ApplyRange();

            ASSERT(!IsEmpty());

            First();
            while (!Eof)
              {
                Edit();
                switch (lLettragesAModifier.back().FlagLettrage)
                  {
                    case HIFLAG_LETTRAGE_LETTRE_IMPORTE:
                      pfldFlagLettrage->AsInteger = HIFLAG_LETTRAGE_LETTRE_IMPORTE_NP1;
                      break;
                    case HIFLAG_LETTRAGE_LETTRE_IMPORTE_NP1:
                      pfldFlagLettrage->AsInteger = HIFLAG_LETTRAGE_LETTRE_IMPORTE;
                      break;
                    case HIFLAG_LETTRAGE_LETTRE_EIC:
                      pfldFlagLettrage->AsInteger = HIFLAG_LETTRAGE_LETTRE_NP1;
                      break;
                    case HIFLAG_LETTRAGE_LETTRE_NP1:
                      pfldFlagLettrage->AsInteger = HIFLAG_LETTRAGE_LETTRE_EIC;
                      break;
                    default:
                      ASSERT(false);
                  }
                Post();
              }
            lLettragesAModifier.pop_back();
          }
      }


    ////////////////////////////////////////////////////////////////////////////////////////
    // Libération de l'index et RAZ, dans le PC, des comptes qui ne sont plus mouvementés //
    ////////////////////////////////////////////////////////////////////////////////////////
    tag = TAG(308);
    IndexName = strOldIndex;
    RAZCptNonMouvementes(ptblPC, lstcptDeleted);
  } catch(Exception& e) {
    IndexName = strOldIndex;
    throw EUser(tag, e);
  }
} /* TTableHI::RectifierEcriture() */




/*
  Cette fonction recalcule le solde N après un changement de date de fin N (date de cloture).
*/
void __fastcall TTableHI::RecalculerSoldeN(TTablePC *tblPC,const TDateTime &AncienneDateFinEx,const TDateTime &NouvelleDateFinEx)
{
  bool ClotureRepoussee;
  CBarre *Barre;
  FilterID FiltreID(FID_NUL);
  TStringField *tblHICompte((TStringField *)FieldByName(strfHI_Compte));
  TStringField *tblHILettrage((TStringField *)FieldByName(strfHI_Lettrage));
  TIntegerField *tblHIFlagLettrage((TIntegerField *)FieldByName(strfHI_FlagLettrage));
  TDateTimeField *tblHIDateImputation((TDateTimeField *)FieldByName(strfHI_DateImputation));

  ASSERT(!tblPC->Database->InTransaction);

  if (AncienneDateFinEx == NouvelleDateFinEx)
    return;                                      //Dates fin exercice identiques, rien à faire
  try
    {
      Barre = new CBarre();
      Barre->Titre = "Recalcul des soldes sur N";
      Barre->Messages = "Initialisation\n"
                        "Mise à jour du lettrage";
      Barre->Open();
      (*Barre) = 0;
      ClotureRepoussee = (AncienneDateFinEx < NouvelleDateFinEx);    //La cloture a-t-elle été repoussée ?
      PushFilter(FiltreID,strfHI_DateImputation + ">'" +
                          (ClotureRepoussee ? AncienneDateFinEx : NouvelleDateFinEx) +
                          "' and " szfHI_DateImputation "<='" +
                          (ClotureRepoussee ? NouvelleDateFinEx : AncienneDateFinEx) + "'");       //On filtre que les écritures entre les 2 dates
      Barre->NextMessage();
    }
  catch(Exception &e)
    {
      delete Barre;
      Barre = 0;
      PopFilter(FiltreID);
      throw EUser(TAG(310),e);
    }
  try
    {//On filtre toujours entre les deux dates
      bool LettrageN;
      int AncienRecNo;
      FilterID FiltreID2;
      (*Barre) = 0;
      Barre->Max = RecordCount;
      First();
      if (ClotureRepoussee)
        {//Certains lettrages N+1 sont sur N maintenant
          while (!Eof)
            {
              if (EstLettreEICNp1)
                {//La ligne est lettrée sur N+1
                  ASSERT(tblHIFlagLettrage->AsInteger == HIFLAG_LETTRAGE_LETTRE_NP1);

                  try
                    {
                      AncienRecNo = RecNo;
                      FiltreID2 = FID_NUL;
                      PushFilter(FiltreID2);
                      FiltrerLettrage(tblHICompte->AsString,tblHILettrage->AsString,HIFLAG_LETTRAGE_LETTRE_NP1);
                      LettrageN = false;
                      while (!(Eof || LettrageN))
                        {
                          LettrageN = (tblHIDateImputation->AsDateTime > NouvelleDateFinEx);       //Y a-t-il une ligne au dela de fin N
                          Next();
                        }
                      if (!LettrageN)
                        {//Le lettrage est totalement sur N
                          First();
                          while (!Eof)
                            {
                              ASSERT(tblHIFlagLettrage->AsInteger == HIFLAG_LETTRAGE_LETTRE_NP1);

                              Edit();
                              tblHIFlagLettrage->AsInteger = HIFLAG_LETTRAGE_LETTRE_EIC;
                              Post();
                            }
                        }
                      PopFilter(FiltreID2);
                      RecNo = AncienRecNo;
                    }
                  catch(Exception &e)
                    {
                      PopFilter(FiltreID2);
                      throw EUser(TAG(312),e);
                    }
                }
              else
                if (EstLettreImporteNp1)
                  {//La ligne est lettrée sur N+1 (importée)
                    ASSERT(tblHIFlagLettrage->AsInteger == HIFLAG_LETTRAGE_LETTRE_IMPORTE_NP1);

                    try
                      {
                        AncienRecNo = RecNo;
                        FiltreID2 = FID_NUL;
                        PushFilter(FiltreID2);
                        FiltrerLettrage(tblHICompte->AsString,tblHILettrage->AsString,HIFLAG_LETTRAGE_LETTRE_IMPORTE_NP1);
                        LettrageN = false;
                        while (!(Eof || LettrageN))
                          {
                            LettrageN = (tblHIDateImputation->AsDateTime > NouvelleDateFinEx);       //Y a-t-il une ligne au dela de fin N
                            Next();
                          }
                        if (!LettrageN)
                          {//Le lettrage est totalement sur N
                            First();
                            while (!Eof)
                              {
                                ASSERT(tblHIFlagLettrage->AsInteger == HIFLAG_LETTRAGE_LETTRE_IMPORTE_NP1);

                                Edit();
                                tblHIFlagLettrage->AsInteger = HIFLAG_LETTRAGE_LETTRE_IMPORTE;
                                Post();
                              }
                          }
                        PopFilter(FiltreID2);
                        RecNo = AncienRecNo;
                      }
                    catch(Exception &e)
                      {
                        PopFilter(FiltreID2);
                        throw EUser(TAG(312),e);
                      }
                  }
              Next();
              (*Barre)++;
            }
        }
      else
        {//Certains lettrages N sont maintenant sur N+1
          while (!Eof)
            {
              if (EstLettreEICN)
                {//La ligne est lettrée sur N, mais devrait être sur N+1
                  ASSERT(tblHIFlagLettrage->AsInteger == HIFLAG_LETTRAGE_LETTRE_EIC);

                  try
                    {
                      AncienRecNo = RecNo;
                      FiltreID2 = FID_NUL;
                      PushFilter(FiltreID2);
                      FiltrerLettrage(tblHICompte->AsString,tblHILettrage->AsString,HIFLAG_LETTRAGE_LETTRE_EIC);
                      while (!Eof)
                        {
                          ASSERT(tblHIFlagLettrage->AsInteger == HIFLAG_LETTRAGE_LETTRE_EIC);

                          Edit();
                          tblHIFlagLettrage->AsInteger = HIFLAG_LETTRAGE_LETTRE_NP1;
                          Post();
                        }
                      PopFilter(FiltreID2);
                      RecNo = AncienRecNo;
                    }
                  catch(Exception &e)
                    {
                      PopFilter(FiltreID2);
                      throw EUser(TAG(313),e);
                    }
                }
              else
                if (EstLettreImporteN)
                  {//La ligne est lettrée sur N, mais devrait être sur N+1 (importée)
                    ASSERT(tblHIFlagLettrage->AsInteger == HIFLAG_LETTRAGE_LETTRE_IMPORTE);

                    try
                      {
                        AncienRecNo = RecNo;
                        FiltreID2 = FID_NUL;
                        PushFilter(FiltreID2);
                        FiltrerLettrage(tblHICompte->AsString,tblHILettrage->AsString,HIFLAG_LETTRAGE_LETTRE_IMPORTE);
                        while (!Eof)
                          {
                            ASSERT(tblHIFlagLettrage->AsInteger == HIFLAG_LETTRAGE_LETTRE_IMPORTE);

                            Edit();
                            tblHIFlagLettrage->AsInteger = HIFLAG_LETTRAGE_LETTRE_IMPORTE_NP1;
                            Post();
                          }
                        PopFilter(FiltreID2);
                        RecNo = AncienRecNo;
                      }
                    catch(Exception &e)
                      {
                        PopFilter(FiltreID2);
                        throw EUser(TAG(313),e);
                      }
                  }
              Next();
              (*Barre)++;
            }
        }
      PopFilter(FiltreID);
      Barre->Close();
      delete Barre;
      Barre = 0;
    }
  catch(Exception &e)
    {
      Barre->Close();
      delete Barre;
      Barre = 0;
      PopFilter(FiltreID);
      throw EUser(TAG(311),e);
    }
}




/*
  Cette fonction réorganise le lettrage après cloture.
    Le lettrage à cheval des à nouveaux non détaillés est supprimé.
    Le lettrage totalement N+1 des à nouveaux non détaillés est passé en lettrage N.
    Le lettrage à cheval des à nouveaux détaillés est passé en lettrage N.
    Le lettrage totalement N+1 des à nouveaux détaillés est passé en lettrage N.
    Le pré-lettrage est conservé même si le pré-lettrage à cheval des à nouveaux non
    détaillés se trouve coupé.
*/
void __fastcall TTableHI::SupprimerAncienLettrageNp1(TTablePC *tblPC,const TDateTime &DateFinExNp1,CBarre *Barre)
{
  class Lettrage
  {
    public:
      Currency Solde;
      bool EcritureSurNp1;
      __fastcall Lettrage(){Solde = 0.0;EcritureSurNp1 = false;};
  };
  TStringField *tblHICompte,*tblHILettrage;
  TIntegerField *tblHIFlagLettrage;
  TCurrencyField *tblHIMontant;
  TBooleanField *tblHIEstCrediteur;
  TDateTimeField *tblHIDateImputation;
  TStringList *Liste;
  Lettrage *LeLettrage;
  int Position;
  AnsiString Chaine;
  try
    {
      Liste = 0;
      IndexName = sziHI_LettrageDate;
      tblHICompte = (TStringField *)FieldByName(strfHI_Compte);
      tblHILettrage = (TStringField *)FieldByName(strfHI_Lettrage);
      tblHIFlagLettrage = (TIntegerField *)FieldByName(strfHI_FlagLettrage);
      tblHIMontant = (TCurrencyField *)FieldByName(strfHI_Montant);
      tblHIEstCrediteur = (TBooleanField *)FieldByName(strfHI_EstCrediteur);
      tblHIDateImputation = (TDateTimeField *)FieldByName(strfHI_DateImputation);
      Barre->Max = RecordCount;
      (*Barre) = 0;
      First();
      Liste = new TStringList;
      while (!Eof)
        {
          if (EstLettre)
            {
              Chaine = tblHICompte->AsString + "\\" + tblHILettrage->AsString + "\\" + tblHIFlagLettrage->AsInteger;
              Position = Liste->IndexOf(Chaine);
              if (Position == -1)
                {
                  LeLettrage = new Lettrage;
                  Liste->AddObject(Chaine,(TObject *)LeLettrage);
                }
              else
                LeLettrage = (Lettrage *)Liste->Objects[Position];
              if (tblHIEstCrediteur->AsBoolean)
                LeLettrage->Solde += tblHIMontant->AsCurrency;
              else
                LeLettrage->Solde -= tblHIMontant->AsCurrency;
              if (tblHIDateImputation->AsDateTime > DateFinExNp1)
                LeLettrage->EcritureSurNp1 = true;
            }
          Next();
          (*Barre)++;
        }
      (*Barre) = 0;
      IndexName = EmptyStr;
      First();
      while (!Eof)
        {
          if (EstLettre)
            {
              Chaine = tblHICompte->AsString + "\\" + tblHILettrage->AsString + "\\" + tblHIFlagLettrage->AsInteger;
              Position = Liste->IndexOf(Chaine);
              if (Position == -1)
                throw EUser(TAGL,"Lettrage non retrouvé.");
              LeLettrage = (Lettrage *)Liste->Objects[Position];
              if (LeLettrage->Solde != 0.0)
                {
                  Edit();
                  tblHILettrage->Clear();
                  tblHIFlagLettrage->AsInteger = HIFLAG_LETTRAGE_NON_LETTRE;
                  Post();
                }
              else
                if (!LeLettrage->EcritureSurNp1)
                  {
                    Edit();
                    if (EstLettreEIC)
                      tblHIFlagLettrage->AsInteger = HIFLAG_LETTRAGE_LETTRE_EIC;
                    else
                      tblHIFlagLettrage->AsInteger = HIFLAG_LETTRAGE_LETTRE_IMPORTE;
                    Post();
                  }
            }
          Next();
          (*Barre)++;
        }
    }
  catch (Exception &e)
    {
      for (int i = 0;i < Liste->Count;i++)
        delete (Lettrage *)Liste->Objects[i];
      delete Liste;
      throw EUser(TAGL,e);
    }
  for (int i = 0;i < Liste->Count;i++)
    delete (Lettrage *)Liste->Objects[i];
  delete Liste;
}




 /*----------------------------------------------------------------------------*\
 ------------- TTableHI::GetEstLettre() -----------------------------------------
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette fonction, de lecture des propriétés "EstLettre*", permet de         -
 - connaître le type du lettrage de l'enregistrement courant.                   -
 -                                                                              -
 - Paramètres :                                                                 -
 -   eTypeLettrage : Type du lettrage à tester (une valeur HIFLAG_LETTRAGE_*)   -
 -                   ou bien 0 si on veut savoir si l'enregistrement courant    -
 -                   est lettré via l'import ou via la fonction de base i.e.    -
 -                   HIFLAG_LETTRAGE_LETTRE_IMPORTE ouHIFLAG_LETTRAGE_LETTRE_EIC-
 -                                                                              -
 - Retour :                                                                     -
 -   TRUE si le lettrage de l'enregistrement courant est du type recherché;     -
 - FALSE sinon.                                                                 -
 \*----------------------------------------------------------------------------*/
 bool __fastcall TTableHI::GetEstLettre(int eTypeLettrage)
 {
  ASSERT(!FieldByName(strfHI_FlagLettrage)->IsNull);

  ///////////////////////////////////////////////////////////////////
  // Détermination du type du lettrage de l'enregistrement courant //
  ///////////////////////////////////////////////////////////////////
  switch (eTypeLettrage)
    {
      case HIFLAG_LETTRAGE_LETTRE_IMPORTE:
      case HIFLAG_LETTRAGE_LETTRE_IMPORTE_NP1:
      case HIFLAG_LETTRAGE_LETTRE_EIC:
      case HIFLAG_LETTRAGE_LETTRE_NP1:
      case HIFLAG_LETTRAGE_PRELETTRE:
      case HIFLAG_LETTRAGE_NON_LETTRE:
        return(FieldByName(strfHI_FlagLettrage)->AsInteger == eTypeLettrage);
      case HIFLAG_LETTRAGE_EST_LETTRE_N:
        return EstLettreEICN || EstLettreImporteN;
      case HIFLAG_LETTRAGE_EST_LETTRE_NP1:
        return EstLettreEICNp1 || EstLettreImporteNp1;
      case HIFLAG_LETTRAGE_EST_LETTRE:
        return EstLettreEIC || EstLettreImporte;
      case HIFLAG_LETTRAGE_EST_LETTRE_EIC:
        return EstLettreEICN || EstLettreEICNp1;
      case HIFLAG_LETTRAGE_EST_LETTRE_IMPORTE:
        return EstLettreImporteN || EstLettreImporteNp1;
      default:
        ASSERT(false);

        return false;
    }
} /* TTableHI::GetEstLettre() */


 /******************************************************************************\
 ************* TTableHI::GetLettrageEstModifie() ********************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction revoie TRUE si le lettrage de l'écriture a été modifié par *
 *    Rev'AO.                                                                   *
 *                                                                              *
 \******************************************************************************/
bool __fastcall TTableHI::GetLettrageEstModifie()
{
  ASSERT(!IsEmpty());

  return (FieldByName(strfHI_Flags)->AsInteger & HIFLAGS_LETTRAGE_EST_MODIFIE);
} /* TTableHI::GetLettrageEstModifie() */


 /*----------------------------------------------------------------------------*\
 ------------- TTableHI::SetLettrageEstModifie() --------------------------------
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette fonction lève le flag HIFLAGS_LETTRAGE_EST_MODIFIE quand TRUE est   -
 -    passé en paramètre.                                                       -
 -                                                                              -
 \*----------------------------------------------------------------------------*/
 void __fastcall TTableHI::SetLettrageEstModifie(bool bEstModifie)
 {
  ASSERT(!IsEmpty());
  ASSERT(State == dsEdit);

  int Flag(FieldByName(strfHI_Flags)->AsInteger | HIFLAGS_LETTRAGE_EST_MODIFIE);         //On force le bit à 1
  if (!bEstModifie)
    Flag = Flag ^ HIFLAGS_LETTRAGE_EST_MODIFIE;            //Le bit doit être à 0 ; 1^1=0
  FieldByName(strfHI_Flags)->AsInteger = Flag;

} /* TTableHI::SetLettrageEstModifie() */


 /******************************************************************************\
 ************* TTableHI::Lettrer() **********************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction lettre la ligne courante avec la chaine passée en          *
 *    paramètre.                                                                *
 *                                                                              *
 \******************************************************************************/
void __fastcall TTableHI::Lettrer(const AnsiString &Lettre,bool Np1)
{
  ASSERT(State == dsEdit);

  FieldByName(strfHI_FlagLettrage)->AsInteger = (Np1 ? HIFLAG_LETTRAGE_LETTRE_NP1 : HIFLAG_LETTRAGE_LETTRE_EIC);
  FieldByName(strfHI_Lettrage)->AsString = Lettre;
  SetLettrageEstModifie(true);
} /* TTableHI::Lettrer() */


void __fastcall TTableHI::LettrerAutoOnFilterRecord( TDataSet *pDataSet, bool &bAccept)
{
  bAccept = LIGNE_EST_NON_LETTRE( FieldByName( strfHI_FlagLettrage)->AsInteger) &&
            ( FieldByName( strfHI_Compte)->AsString==m_strCompteALettrer) &&
            !EstUneLigneAnnulee;
}



int _USERENTRY CompareValueCroissant( const void *pElem1, const void *pElem2)
{
  TLetAuto *pElement1 = ( TLetAuto*)pElem1;
  TLetAuto *pElement2 = ( TLetAuto*)pElem2;
       if( pElement1->curValue>pElement2->curValue) return  1;
  else if( pElement1->curValue<pElement2->curValue) return -1;
  else {
         if( pElement1->dtImput>pElement2->dtImput) return  1;
    else if( pElement1->dtImput<pElement2->dtImput) return -1;
    return 0;
  }
}

bool __fastcall ArrayIsEmpty( TLetAuto *pArray)
{
  bool bReturn = false;
  for( int i=0; !pArray[i].IsLast(); i++) bReturn |= !pArray[i].IsBusy();
  return !bReturn;
}

RET_SEARCH __fastcall TTableHI::ChercherSomme( const TLetAuto &laValue, TLetAuto *pArray,bool &Np1)
{
  RET_SEARCH rs;
  TLetAuto *pLolo;
  TLetAuto laNewValue = laValue;
  bool     bFin       = false;
//  int      nCount     = 1;
  int      i;

  static nEnt = 0;

  nEnt++;

  if ( nEnt>m_nRecurs) { nEnt--; return RS_ABORT; }

  if ( ArrayIsEmpty( pArray)) { nEnt--; return RS_NOK; }

  Application->ProcessMessages();

  for( i=0; !pArray[i].IsLast(); i++) {
    if ( pArray[i].Egal( laValue) && !pArray[i].IsBusy()) {
      m_pSoluce->Add(( void*)pArray[i].nAutoID);
      Np1 |= pArray[i].dtImput > cm_DateFinExercice;
      nEnt--;
      return RS_OK;
    }
//    nCount++;
  }

  for( i=0; !pArray[i].IsLast() && !bFin; i++) {
    Application->ProcessMessages();
    if ( m_frmLettrageAuto->Traitement==TL_ABORT) { nEnt--; return RS_ABORT; } // L'utilisateur en a marre d'attendre
    if ( pArray[i].IsBusy()) continue;
    laNewValue.curValue = laValue.curValue - pArray[i].curValue;
    if ( laNewValue.curValue>0) {
      //TLetAuto *pLolo = NULL;
      //pLolo = new TLetAuto[nCount-i-1]; ASSERT( pLolo);
      //int       a     = 0;
      //for( int j=i+1; j<nCount; j++, a++) pLolo[a] = pArray[j];
      pLolo = pArray + i + 1;
      rs = ChercherSomme( laNewValue, pLolo,Np1);
      if (( rs==RS_ABORT) && ( nEnt>1)) { nEnt--; return RS_ABORT; }
      bFin = ( rs==RS_OK);
      //delete []pLolo;
    } else
      break;
  }

  if ( bFin) {
    Np1 |= pArray[i - 1].dtImput > cm_DateFinExercice;
    m_pSoluce->Add(( void*)pArray[i-1].nAutoID);
    nEnt--;
    return RS_OK;
  }

  nEnt--;
  return RS_NOK;
}

bool __fastcall TTableHI::ChercherLettrage( TLetAuto *pDebit, TLetAuto *pCredit, TIncProgressBar pIncFnc)
{
  TFilterRecordEvent pSaveFilterRecord;
  TLetAuto laValue;
  bool Np1,bAbort = false;
  AnsiString /*strPrelettrage,*/strLettrage = LettrageSuivant(m_strCompteALettrer);

  m_pSoluce = new TList();
  for( int i=0; !pDebit[i].IsLast(); i++) {
    Application->ProcessMessages();
    if ( !pDebit[i].IsBusy()) {
      laValue = pDebit[i];
      m_pSoluce->Clear();
      Np1 = false;
      if ( ChercherSomme( laValue, pCredit,Np1)==RS_OK) {
        // On a touvé un lettrage à faire
        for( int k=0; k<m_pSoluce->Count; k++) {
          int nAutoID = ( int)m_pSoluce->Items[k];
          ASSERT( FieldByName( strfHI_Compte)->AsString==m_strCompteALettrer);
          for( int j=0; !pCredit[j].IsLast(); j++)
            if( pCredit[j].nAutoID==nAutoID) { pCredit[j].bUsed = true; break; }
        }
        m_pSoluce->Add(( void*)pDebit[i].nAutoID); pDebit[i].bUsed = true;
        Np1 |= pDebit[i].dtImput > cm_DateFinExercice;
        AjouterListeLettrage(m_pSoluce,strLettrage,Np1);
        IncLettre(strLettrage);
      }
    }
    pIncFnc();
    // L'utilisateur a t-il abandonné le traitement
    if ( m_frmLettrageAuto->Traitement==TL_ABORT) { bAbort = true; break; }
  }
  delete m_pSoluce;
  m_pSoluce = NULL;
  return !bAbort;
}

bool __fastcall TTableHI::LettrageAutomatique()
{
  TBooleanField *EstCrediteur;
  TIntegerField *CodeDevise,*AutoID;
  TFloatField *TauxChange;
  TDateTimeField *DateImputation;
  TCurrencyField *Montant;
  EICTag              nTag = TAGL;
  bool                bAbort = false;
  try {

        EstCrediteur = (TBooleanField *)FieldByName(strfHI_EstCrediteur);
        CodeDevise = (TIntegerField *)FieldByName(strfHI_CodeDevise);
        AutoID = (TIntegerField *)FieldByName(strfHI_AutoID);
        TauxChange = (TFloatField *)FieldByName(strfHI_TauxChange);
        DateImputation = (TDateTimeField *)FieldByName(strfHI_DateImputation);
        Montant = (TCurrencyField *)FieldByName(strfHI_Montant);
                // Créer 2 tableaux dont un contient tous les débits
                // et un autre tous les crédits
                // Calcule le nombre de débit et de crédit
                int nCountDebit=0, nCountCredit=0;
nTag = TAG( 3); First();
                while( !Eof) {
                  if (EstCrediteur->AsBoolean) nCountCredit++;
                                          else nCountDebit++;
                  Next();
                }
                // Remplit les 2 tableaux
                TLetAuto *pDebitArray, *pCreditArray;
nTag = TAG( 4); pDebitArray  = new TLetAuto[nCountDebit +1]; pDebitArray [ nCountDebit].curValue.Val=CUR_MAX;
                pCreditArray = new TLetAuto[nCountCredit+1]; pCreditArray[nCountCredit].curValue.Val=CUR_MAX;
                m_frmLettrageAuto->pbDebits ->Max = nCountDebit;
                m_frmLettrageAuto->pbCredits->Max = nCountCredit;
                First(); nCountDebit = nCountCredit = 0;
nTag = TAG( 5); while( !Eof) {
                  if( EstCrediteur->AsBoolean) {
                    pCreditArray[nCountCredit  ].bUsed    = false;
                    pCreditArray[nCountCredit  ].nAutoID  = AutoID->AsInteger;
                    pCreditArray[nCountCredit  ].Devise   = CodeDevise->AsInteger;
                    pCreditArray[nCountCredit  ].dTauxChg = TauxChange->AsFloat;
                    pCreditArray[nCountCredit  ].dtImput  = DateImputation->AsDateTime;
                    pCreditArray[nCountCredit++].curValue = Montant->AsCurrency;
                  } else {
                    pDebitArray [nCountDebit   ].bUsed    = false;
                    pDebitArray [nCountDebit   ].nAutoID  = AutoID->AsInteger;
                    pDebitArray [nCountDebit   ].Devise   = CodeDevise->AsInteger;
                    pDebitArray [nCountDebit   ].dTauxChg = TauxChange->AsFloat;
                    pDebitArray [nCountDebit   ].dtImput  = DateImputation->AsDateTime;
                    pDebitArray [nCountDebit ++].curValue = Montant->AsCurrency;
                  }
                  Next();
                }
                // Tri des tableaux dans l'ordre décroissant
nTag = TAG( 6); qsort( pDebitArray , nCountDebit , sizeof(TLetAuto), CompareValueCroissant);
                qsort( pCreditArray, nCountCredit, sizeof(TLetAuto), CompareValueCroissant);
                // Cherche les lettrages possibles
nTag = TAG( 7); if ( ChercherLettrage( pDebitArray , pCreditArray, m_frmLettrageAuto->IncDebit )) {
nTag = TAG( 8);   if ( !ChercherLettrage( pCreditArray, pDebitArray , m_frmLettrageAuto->IncCredit)) bAbort = true;
                } else bAbort = true;
                // C'est fini
                delete[] pDebitArray;
                delete[] pCreditArray;
                Filtered       = false;
                OnFilterRecord = NULL;
  } catch ( Exception &e) {
    Filtered       = false;
    OnFilterRecord = NULL;
    throw EUser( nTag, e);
  }
   return !bAbort;
}

class SoldeLettrage
{
public:
  Currency Solde;
  bool Np1;
  __fastcall SoldeLettrage()
    {
      Solde = 0.0;
      Np1 = false;
    }
  __fastcall SoldeLettrage(const SoldeLettrage &ls)
    {
      Solde = ls.Solde;
      Np1 = ls.Np1;
    }
  __fastcall ~SoldeLettrage()
    {
    }
};
typedef map<AnsiString,SoldeLettrage> MapPieces;
typedef MapPieces::iterator MapPieceIT;
typedef map<int,AnsiString> MapAutoID;
typedef MapAutoID::iterator MapAutoIDIT;
class LigneLettrageCombi
{
public:
  int AutoID;
  Currency Montant;
  bool Np1,Supprime;
  __fastcall LigneLettrageCombi()
    {
      AutoID = 0;
      Montant = 0.0;
      Np1 = Supprime = false;
    }
  __fastcall LigneLettrageCombi(const LigneLettrageCombi &llc)
    {
      AutoID = llc.AutoID;
      Montant = llc.Montant;
      Np1 = llc.Np1;
      Supprime = llc.Supprime;
    }
  __fastcall ~LigneLettrageCombi()
    {
    }
};
typedef vector<LigneLettrageCombi> VectorLigneLettrageCombi;
typedef VectorLigneLettrageCombi::iterator VectorLigneLettrageCombiIT;
typedef vector<VectorLigneLettrageCombiIT> VectorVectorLigneLettrageCombiIT;
typedef VectorVectorLigneLettrageCombiIT::iterator VectorVectorLigneLettrageCombiITIT;
VectorLigneLettrageCombi ListeDebits,ListeCredits/*,*Liste1,*Liste2*/;

bool __fastcall TTableHI::LettrageCombinatoire(unsigned int Profondeur,unsigned int ProfondeurMax,AnsiString &Lettrage)
{
  unsigned int n;
  bool Np1;
  static VectorLigneLettrageCombi *Liste1,*Liste2;
  static VectorLigneLettrageCombiIT Liste1IT,Liste2IT,vListe2[20],*vListe2IT,*vListe2ITDernier;
  static VectorVectorLigneLettrageCombiIT vListe1;
  static Currency Solde,MontantDeReference;
  for (int i = (Profondeur == 1 ? 1 : 0);i < 2;i++)  //Le test 1-1 doit être fait qu'une seule fois
    {
      ASSERT(vListe1.size() == 0);

      Application->ProcessMessages();
      if (!ListeDebits.size() || !ListeCredits.size() || (m_frmLettrageAuto->Traitement == TL_ABORT))
        break;
      Liste1 = i ? &ListeCredits : &ListeDebits;
      Liste2 = i ? &ListeDebits : &ListeCredits;
      Liste1IT = Liste1->begin();
      while (Liste1IT != Liste1->end())
        {//On parcourt la première liste
          Application->ProcessMessages();
          if ((Liste2->size() < Profondeur)  || (m_frmLettrageAuto->Traitement == TL_ABORT))
            break;   //Il ne reste plus assez de montant dans la seconde liste pour le lien 1-Profondeur
          Solde = MontantDeReference = Liste1IT->Montant;   //On initialise les montants pour la recherche
          vListe2IT = &(vListe2[0] = Liste2->begin());      //On place le premier pointeur sur le premier de la liste
          vListe2ITDernier = &vListe2[Profondeur - 1];
          goto ChercherLettrage;                            //On commence la recherche
          while (true)
            {//Tant qu'on arrive à avancer
              (*vListe2IT)++;         //On essaie d'avancer le pointeur
              if (*vListe2IT == Liste2->end())
                {//On est à la fin
                  if (vListe2IT == vListe2)
                    goto FinLettrage;                  //C'était le premier pointeur, il n'y a plus de solution possible
                  vListe2IT--;        //On prend le pointeur d'avant pour essayer de l'avancer

                  ASSERT(*vListe2IT != Liste2->end());   //Le pointeur précédent ne doit pas être à la fin

                  Solde += (*vListe2IT)->Montant;        //On cherche désormais ce nouveau montant
                }
              else
                {
                  ChercherLettrage:
                  if ((*vListe2IT)->Montant > Solde)
                    continue;                             //Le montant est supérieur, ce n'est pas la peine de continuer avec ce montant
                  if (vListe2IT == vListe2ITDernier)
                    {//On a tous nos pointeurs d'affectés
                      if ((*vListe2IT)->Montant == Solde)
                        goto LettrageEquilibre;           //On a trouvé un lettrage équilibré
                      continue;                           //Le montant est inférieur, on continue la recherche
                    }
                  Solde -= (Liste2IT = *(vListe2IT++))->Montant;             //On cherche désormais ce nouveau montant
                  *vListe2IT = Liste2IT;                  //On place le prochain pointeur au même endroit que le pointeur courant
                }
            }
          LettrageEquilibre:       //On a trouvé un lettrage à faire
          if (Lettrage.IsEmpty())
            Lettrage = LettrageSuivant(m_strCompteALettrer);
          else
            IncLettre(Lettrage);
          m_pSoluce->Clear();
          m_pSoluce->Add((void *)Liste1IT->AutoID);            //On lettre l'iterator de la liste 1
          Np1 = Liste1IT->Np1;
          for (vListe2IT = vListe2,n = 0;n < Profondeur;n++)
            {
              Np1 |= (*vListe2IT)->Np1;
              m_pSoluce->Add((void *)(*(vListe2IT++))->AutoID);    //avec les n iterator de la liste 2
            }
          AjouterListeLettrage(m_pSoluce,Lettrage,Np1);
          m_pSoluce->Clear();
          vListe1.push_back(Liste1IT);    //On supprimera la ligne de la liste 1 plus tard
          for (n = 0;n < ProfondeurMax - Profondeur;n++)
            if (i)
              m_frmLettrageAuto->IncCredit();
            else
              m_frmLettrageAuto->IncDebit();
          while (true)
            {
              if (i)
                m_frmLettrageAuto->IncDebit();
              else
                m_frmLettrageAuto->IncCredit();
              Liste2->erase(*vListe2ITDernier);//On supprime les n lignes lettrées
              if (vListe2ITDernier == vListe2)
                break;
              vListe2ITDernier--;
            }
          FinLettrage:                    //On continue avec un autre iterator de la liste 1
          Liste1IT++;
          if (i)
            m_frmLettrageAuto->IncCredit();
          else
            m_frmLettrageAuto->IncDebit();
        }
      while (vListe1.size())
        {
          Liste1->erase(vListe1.back());  //On supprime les lignes lettrées en attente
          vListe1.pop_back();
        }
    }
  return (Profondeur == ProfondeurMax) ? (m_frmLettrageAuto->Traitement != TL_ABORT) : LettrageCombinatoire(++Profondeur,ProfondeurMax,Lettrage);
}



bool __fastcall TTableHI::LettrageCombinatoire(unsigned int Profondeur)
{
  AnsiString Lettrage;
  m_frmLettrageAuto->InitDebitCredit(ListeDebits.size() * (Profondeur + 1),ListeCredits.size() * (Profondeur + 1));
  LettrageCombinatoire(1,Profondeur,Lettrage);
  return m_frmLettrageAuto->Traitement != TL_ABORT;
}

typedef list<AnsiString> PiecesDUnPrelettrage;
typedef PiecesDUnPrelettrage::iterator PiecesDUnPrelettrageIT;
typedef map<AnsiString,PiecesDUnPrelettrage> MapPrelettragePieces;
typedef MapPrelettragePieces::iterator MapPrelettragePiecesIT;

class LignePourCompteSolde
{
public:
  int AutoID;
  bool LettrageNp1;
  AnsiString Lettre;
  Currency Montant;
  __fastcall LignePourCompteSolde()
    {
      AutoID = 0;
      LettrageNp1 = false;
      Lettre = EmptyStr;
      Montant = 0.0;
    }
  __fastcall LignePourCompteSolde(const LignePourCompteSolde &l)
    {
      AutoID = l.AutoID;
      LettrageNp1 = l.LettrageNp1;
      Lettre = l.Lettre;
      Montant = l.Montant;
    }
};
typedef list<LignePourCompteSolde> ListLignePourCompteSolde;



void __fastcall TTableHI::LettrerAutomatique( const AnsiString &strCompte, TYPE_LETTRAGE *tLettrage, int *Recurs, CTable *ptblHI2)
{
  EICTag              nTag;
  HWND handle;
  TRAITEMENT_LETTRAGE eTraitement;
  TStringField *Piece,*Compte,*Lettrage;
  TCurrencyField *Montant;
  TBooleanField *EstCrediteur;
  TIntegerField *AutoID,*Flags,*FlagLettrage;
  TDateTimeField *DateImputation;
  TTablePC *tblPC = NULL;
  TStringList        *pLstCompte = NULL;
  TStringList        *ListePieces = NULL;
  Currency CurCredit,CurDebit,Solde;
  AnsiString strLettrage,Prelettrage;

  ASSERT( !Filtered);
  ASSERT( Filter.IsEmpty());

  try {
                    handle = Screen->ActiveForm->Handle;
                    pLstCompte = new TStringList();
                    pLstCompte->CommaText = strCompte;
                    // Disable tous les fenêtres de l'application
                    // sauf la fenêtre d'attente
    nTag = TAG( 1); m_frmLettrageAuto = NULL;
                    m_frmLettrageAuto = new TfrmLettrageAuto(NULL, *tLettrage, *Recurs);
                    m_frmLettrageAuto->Show();
                    m_frmLettrageAuto->Refresh();
                    void *pTaskWindow = DisableTaskWindows( m_frmLettrageAuto->Handle);
                    // Attend que l'utilisateur ait choisi un traitement à faire
                    while (( eTraitement=m_frmLettrageAuto->Traitement)==TL_WAIT) Application->ProcessMessages();
                    if ( eTraitement==TL_ABORT) goto lblStop;
                    // Pose le filtre sur le HI
                    if (m_frmLettrageAuto->rbCombinatoire->Checked)
                    {
                      *tLettrage = LETTRAGE_COMBINATOIRE;
                      *Recurs = m_frmLettrageAuto->Recursion;
                      m_frmLettrageAuto->pbComptes->Max = pLstCompte->Count;
                      m_frmLettrageAuto->pbComptes->Position = 0;
                      m_nRecurs = m_frmLettrageAuto->Recursion;
                      for( int i=0; i<pLstCompte->Count; i++) {
                      m_frmLettrageAuto->Compte = pLstCompte->Strings[i];
    nTag = TAG( 2);   m_strCompteALettrer       = pLstCompte->Strings[i];
                      OnFilterRecord            = LettrerAutoOnFilterRecord;
                      Filtered                  = true;
                      if (!LettrageAutomatique())
                        break;
                    }
                    m_frmLettrageAuto->pbComptes->Position = 0;
                    if (m_frmLettrageAuto->Traitement != TL_ABORT)
                      LettrerListeLettrage();
                    }
                    else if (m_frmLettrageAuto->rbPieceInterne->Checked || m_frmLettrageAuto->rbPieceExterne->Checked)
                    {
                      bool CompteAPrendre;
                      MapPieces mapPieces;
                      MapPieceIT mpit;
                      MapPrelettragePieces mplp;
                      MapAutoID mapAutoID;
                      MapAutoIDIT mait;
                      MapPrelettragePiecesIT mplpit;
                      PiecesDUnPrelettrageIT pplit;
                      SoldeLettrage sl;

                      ASSERT(IndexName.IsEmpty());

                      try
                        {
                          if (IsEmpty())
                            return;
                          if (pLstCompte->Count == 1)
                            {
                              Filter = "Compte='" + pLstCompte->Strings[0] + "'";
                              Filtered = true;
                            }
                          tblPC = new TTablePC(NULL);
                          m_pSoluce = new TList();
                          IndexName = sziHI_LettrageDate;
                          EstCrediteur = (TBooleanField *)FieldByName(strfHI_EstCrediteur);
                          Montant = (TCurrencyField *)FieldByName(strfHI_Montant);
                          AutoID = (TIntegerField *)FieldByName(strfHI_AutoID);
                          Flags = (TIntegerField *)FieldByName(strfHI_Flags);
                          FlagLettrage = (TIntegerField *)FieldByName(strfHI_FlagLettrage);
                          Lettrage = (TStringField *)FieldByName(strfHI_Lettrage);
                          Compte = (TStringField *)FieldByName(strfHI_Compte);
                          if(m_frmLettrageAuto->rbPieceInterne->Checked)
                               Piece = (TStringField *)FieldByName(strfHI_Piece);
                          else Piece = (TStringField *)ptblHI2->FieldByName(strfHI_PieceExterne);
                          DateImputation = (TDateTimeField *)FieldByName(strfHI_DateImputation);
                          tblPC->Open();
                          m_frmLettrageAuto->pbComptes->Max = RecordCount * 2;
                          First();
                          m_strCompteALettrer = EmptyStr;
                          do
                            {
                              Application->ProcessMessages();
                              if (m_frmLettrageAuto->Traitement == TL_ABORT)
                                break;
                              if ((Compte->AsString != m_strCompteALettrer) || Eof)
                                {//On change de compte ou on est à la fin
                                  for (mplpit = mplp.begin();mplpit != mplp.end();mplpit++)
                                    if (mplpit->second.size() >= 2)
                                      {//Il y a plusieurs pièces pour un même prélettrage, on ne lettre pas ces pièces
                                        for (pplit = mplpit->second.begin();pplit != mplpit->second.end();pplit++)
                                          {
                                            mpit = mapPieces.find(*pplit);

                                            ASSERT(mpit != mapPieces.end());

                                            mpit->second.Solde = 1.0;  //Pour le rendre déséquilibré, et donc pour ne pas le lettrer
                                          }
                                      }
                                  strLettrage = EmptyStr;
                                  for (mpit = mapPieces.begin();mpit != mapPieces.end();mpit++)
                                    if (mpit->second.Solde == 0.0)
                                      {//Cette pièce est équilibrée, on peut la lettrer
                                        if (strLettrage.IsEmpty())
                                          strLettrage = LettrageSuivant(m_strCompteALettrer);
                                        else
                                          IncLettre(strLettrage);

                                        ASSERT(!m_pSoluce->Count);

                                        for (mait = mapAutoID.begin();mait != mapAutoID.end();mait++)
                                          if (mait->second == mpit->first)        //On recherche tous les AutoID à lettrer pour cette pièce
                                            m_pSoluce->Add((void *)mait->first);
                                        AjouterListeLettrage(m_pSoluce,strLettrage,mpit->second.Np1);
                                        m_pSoluce->Clear();
                                      }
                                  mapPieces.clear();    //On vide les listes du compte précédent
                                  mapAutoID.clear();
                                  if (Eof)
                                    break;   //On a fini
                                  m_strCompteALettrer = Compte->AsString;
                                  CompteAPrendre = pLstCompte->IndexOf(m_strCompteALettrer) != -1;
                                  m_frmLettrageAuto->InfoCompte = strCompte;
                                  sl.Np1 = false;
                                }
                              if (CompteAPrendre && !Piece->IsNull && (LIGNE_EST_NON_LETTRE(FlagLettrage->AsInteger) || LIGNE_EST_PRELETTRE(FlagLettrage->AsInteger)) && !LIGNE_EST_ANNULEE(Flags->AsInteger))
                                {//La ligne n'est pas léttrée, on l'ajoute à la liste des lignes potentiellement lettrables
                                  mpit = mapPieces.find(Piece->AsString);
                                  if (mpit == mapPieces.end())
                                    {//C'est la première fois que l'on voit cette pièce
                                      sl.Solde = EstCrediteur->AsBoolean ? -Montant->AsCurrency : Montant->AsCurrency;
                                      sl.Np1 = DateImputation->AsDateTime > cm_DateFinExercice;
                                      mapPieces.insert(MapPieces::value_type(Piece->AsString,sl));
                                    }
                                  else
                                    {//On a déjà vu cette pièce
                                      mpit->second.Solde += EstCrediteur->AsBoolean ? -Montant->AsCurrency : Montant->AsCurrency;
                                      mpit->second.Np1 |= DateImputation->AsDateTime > cm_DateFinExercice;
                                    }
                                  mapAutoID.insert(MapAutoID::value_type(AutoID->AsInteger,Piece->AsString));
                                  if (LIGNE_EST_PRELETTRE(FlagLettrage->AsInteger))
                                    {
                                      mplpit = mplp.find(Lettrage->AsString);
                                      if (mplpit == mplp.end())
                                        mplp.insert(MapPrelettragePieces::value_type(Lettrage->AsString,PiecesDUnPrelettrage())).first->second.push_back(Piece->AsString);
                                      else
                                        {
                                          bool Trouve = false;
                                          for (pplit = mplpit->second.begin();pplit != mplpit->second.end();pplit++)
                                            if (*pplit == Piece->AsString)
                                              {
                                                Trouve = true;
                                                break;
                                              }
                                          if (!Trouve)
                                            mplpit->second.push_back(Piece->AsString);
                                        }
                                    }
                                }
                              Next();
                              m_frmLettrageAuto->Inc();
                            }
                          while (true);
                          if (m_frmLettrageAuto->Traitement != TL_ABORT)
                            LettrerListeLettrage();
                          Filtered = false;
                          Filter = EmptyStr;
                        }
                      catch (Exception &e)
                        {
                          EICDisplayException(TAGL,e);
                        }
                      delete tblPC;
                      tblPC = NULL;
                      delete m_pSoluce;
                      m_pSoluce = NULL;
                    }
                    else if (m_frmLettrageAuto->rbSoldes->Checked)
                    {
                      bool CompteAPrendre,LettrageNp1;
                      ListLignePourCompteSolde::iterator ListeIT,ListeIT2;
                      ListLignePourCompteSolde Liste;
                      LignePourCompteSolde ligne;

                      ASSERT(IndexName.IsEmpty());

                      try
                        {
                          if (IsEmpty())
                            return;
                          if (pLstCompte->Count == 1)
                            {
                              Filter = "Compte='" + pLstCompte->Strings[0] + "'";
                              Filtered = true;
                            }
                          tblPC = new TTablePC(NULL);
                          m_pSoluce = new TList();
                          IndexName = striHI_Comptes;
                          EstCrediteur = (TBooleanField *)FieldByName(strfHI_EstCrediteur);
                          Montant = (TCurrencyField *)FieldByName(strfHI_Montant);
                          AutoID = (TIntegerField *)FieldByName(strfHI_AutoID);
                          Flags = (TIntegerField *)FieldByName(strfHI_Flags);
                          FlagLettrage = (TIntegerField *)FieldByName(strfHI_FlagLettrage);
                          Lettrage = (TStringField *)FieldByName(strfHI_Lettrage);
                          Compte = (TStringField *)FieldByName(strfHI_Compte);
                          DateImputation = (TDateTimeField *)FieldByName(strfHI_DateImputation);
                          tblPC->Open();
                          m_frmLettrageAuto->pbComptes->Max = RecordCount * 2;
                          First();
                          m_strCompteALettrer = EmptyStr;
                          do
                            {
                              Application->ProcessMessages();
                              if (m_frmLettrageAuto->Traitement == TL_ABORT)
                                break;
                              if ((Compte->AsString != m_strCompteALettrer) || Eof)
                                {//On change de compte
                                  CompteAPrendre = pLstCompte->IndexOf(Compte->AsString) != -1;
                                  Solde = 0.0;
                                  LettrageNp1 = false;
                                  strLettrage = EmptyStr;
                                  for (ListeIT = Liste.begin();ListeIT != Liste.end();ListeIT++)
                                    if ((*ListeIT).AutoID)
                                      {//La ligne est valide
                                        Solde += (*ListeIT).Montant;
                                        m_pSoluce->Add((void *)(*ListeIT).AutoID);
                                        LettrageNp1 |= (*ListeIT).LettrageNp1;
                                        if (!(*ListeIT).Lettre.IsEmpty())
                                          {//On a affaire à un prélettrage, on prend donc le reste du prélettrage
                                            ListeIT2 = ListeIT;
                                            for (ListeIT2++;ListeIT2 != Liste.end();ListeIT2++)
                                              if ((*ListeIT2).Lettre == (*ListeIT).Lettre)
                                                {
                                                  ASSERT((*ListeIT2).AutoID);  //La ligne doit être valide

                                                  Solde += (*ListeIT2).Montant;
                                                  m_pSoluce->Add((void *)(*ListeIT2).AutoID);
                                                  LettrageNp1 |= (*ListeIT2).LettrageNp1;
                                                  (*ListeIT2).AutoID = 0;  //Pour ne plus reprendre cette ligne
                                                }
                                          }
                                        if (Solde == 0.0)
                                          {//On a trouvé un lettrage à faire
                                            ASSERT(m_pSoluce->Count);

                                            if (strLettrage.IsEmpty())
                                              strLettrage = LettrageSuivant(m_strCompteALettrer);
                                            else
                                              IncLettre(strLettrage);
                                            AjouterListeLettrage(m_pSoluce,strLettrage,LettrageNp1);
                                            m_pSoluce->Clear();
                                          }
                                      }
                                  m_strCompteALettrer = Compte->AsString;
                                  m_pSoluce->Clear();
                                  Liste.clear();
                                }
                              if (Eof)
                                break;   //On a fini
                              if (CompteAPrendre && (LIGNE_EST_NON_LETTRE(FlagLettrage->AsInteger) || LIGNE_EST_PRELETTRE(FlagLettrage->AsInteger)) && !LIGNE_EST_ANNULEE(Flags->AsInteger))
                                {//La ligne n'est pas léttrée, on l'ajoute à la liste des lignes potentiellement lettrables
                                  ligne.AutoID = AutoID->AsInteger;
                                  ligne.LettrageNp1 = DateImputation->AsDateTime > cm_DateFinExercice;
                                  ligne.Lettre = Lettrage->AsString;
                                  ligne.Montant = EstCrediteur->AsBoolean ? -Montant->AsCurrency : Montant->AsCurrency;
                                  Liste.push_back(ligne);
                                }
                              Next();
                              m_frmLettrageAuto->Inc();
                            }
                          while (true);
                          if (m_frmLettrageAuto->Traitement != TL_ABORT)
                            LettrerListeLettrage();
                          Filtered = false;
                          Filter = EmptyStr;
                        }
                      catch (Exception &e)
                        {
                          EICDisplayException(TAGL,e);
                        }
                      delete tblPC;
                      tblPC = NULL;
                      delete m_pSoluce;
                      m_pSoluce = NULL;
                    }
                    else ASSERT(false);

lblStop:            // Réactive tous les fenêtres de l'application
    nTag = TAG( 9); m_frmLettrageAuto->Close();
                    EnableTaskWindows( pTaskWindow);
                    delete m_frmLettrageAuto;
                    m_frmLettrageAuto = NULL;
                    delete pLstCompte;
                    pLstCompte = NULL;
                    delete ListePieces;
                    ListePieces = NULL;
                    ::SetForegroundWindow(handle);

  } catch ( Exception &e) {
    delete m_pSoluce;
    m_pSoluce = NULL;
    delete tblPC;
    delete m_frmLettrageAuto;
    delete pLstCompte;
    delete ListePieces;
    Filtered       = false;
    OnFilterRecord = NULL;
    throw EUser( nTag, e);
  }

}



class UnLettrage
{
public:
  bool LettrageNp1;
  AnsiString Lettrage;
  __fastcall UnLettrage()
    {
      LettrageNp1 = false;
      Lettrage = EmptyStr;
    }
  __fastcall UnLettrage(const UnLettrage &unlettrage)
    {
      LettrageNp1 = unlettrage.LettrageNp1;
      Lettrage = unlettrage.Lettrage;
    }
  __fastcall ~UnLettrage()
    {
    }
};
typedef map<int,UnLettrage> MapLettrage;
typedef MapLettrage::iterator MapLettrageIT;
MapLettrage mapLettrage;



void __fastcall TTableHI::AjouterListeLettrage(TList *ListeAutoID,const AnsiString &Lettrage,bool LettrageNp1) const
{
  UnLettrage unlettrage;
  unlettrage.LettrageNp1 = LettrageNp1;
  unlettrage.Lettrage = Lettrage;
  for (int i = 0;i < ListeAutoID->Count;i++)
    mapLettrage.insert(MapLettrage::value_type((int)ListeAutoID->Items[i],unlettrage));
}



void __fastcall TTableHI::LettrerListeLettrage()
{
  TIntegerField *AutoID;
  MapLettrageIT lettrageit;
  try
    {
      IndexName = EmptyStr;
      AutoID = (TIntegerField *)FieldByName(strfHI_AutoID);
      m_frmLettrageAuto->InfoCompte = EmptyStr;
      SCAN_TABLE(this)
        {
          Application->ProcessMessages();
          lettrageit = mapLettrage.find(AutoID->AsInteger);
          if (lettrageit != mapLettrage.end())
            {
              m_frmLettrageAuto->DebutLettrage();
              Edit();
              Lettrer(lettrageit->second.Lettrage,lettrageit->second.LettrageNp1);
              Post();
              m_frmLettrageAuto->FinLettrage();
            }
          //m_frmLettrageAuto->Inc();
        }
    }
  catch (Exception &e)
    {
      EICDisplayException(TAGL,e);
    }
  mapLettrage.clear();
}



 /******************************************************************************\
 ************* TTableHI::Prelettrer() *******************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction prélettre la ligne courante avec la chaine passée en       *
 *    paramètre.                                                                *
 *                                                                              *
 \******************************************************************************/
void __fastcall TTableHI::Prelettrer(const AnsiString &Lettre)
{
  ASSERT(State == dsEdit);

  FieldByName(strfHI_FlagLettrage)->AsInteger = HIFLAG_LETTRAGE_PRELETTRE;
  FieldByName(strfHI_Lettrage)->AsString = Lettre;
  SetLettrageEstModifie(true);
} /* TTableHI::Prelettrer() */




 /******************************************************************************\
 ************* TTableHI::Delettrer() ********************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction délettre une ligne d'un lettrage ou d'un pré-lettrage.     *
 *                                                                              *
 *    Paramètres :                                                              *
 *      eActionDelettrage : Type d'action à faire                               *
 *                                                                              *
 \******************************************************************************/
void __fastcall TTableHI::Delettrer(enum HIActionDelettrage eActionDelettrage)
{
  enum HIFlagLettrage FlagLettrage;
  TTableHI *tblHI;
  TStringField * HI_Lettrage((TStringField *)FieldByName(strfHI_Lettrage));
  TIntegerField *HI_FlagLettrage((TIntegerField *)FieldByName(strfHI_FlagLettrage)) ;
  tblHI = 0;
  try
    {
  switch (eActionDelettrage)
    {
      case HIAD_DELETTRER_LA_LIGNE_ET_PRELETTRER_LE_RESTE: //On supprime le lettrage de la ligne et on passe le reste en pré-lettrage
      case HIAD_PRELETTRER_LE_TOUT:              //On passe tout le lettrage en pré-lettrage
        {
          int AutoIDLigneASupprimer;
          bool NePasPrelettrer;
          TIntegerField *tblHIAutoID;
          AnsiString Lettre,strCompte,Prelettrage;
          FlagLettrage = (enum HIFlagLettrage)((TIntegerField *)FieldByName(strfHI_FlagLettrage))->AsInteger;
          strCompte = FieldByName(strfHI_Compte)->AsString;
          Lettre = HI_Lettrage->AsString;
          if (eActionDelettrage == HIAD_DELETTRER_LA_LIGNE_ET_PRELETTRER_LE_RESTE)
            AutoIDLigneASupprimer = ((TIntegerField *)FieldByName(strfHI_AutoID))->AsInteger;
          else
            AutoIDLigneASupprimer = -1;
          tblHI = CreerTableLettrage(0,0,0,0);
          tblHIAutoID = (TIntegerField *)tblHI->FieldByName(strfHI_AutoID);
          tblHI->FiltrerLettrageRange(strCompte,Lettre,FlagLettrage);
          Prelettrage = PrelettrageSuivant(strCompte);
          tblHI->First();
          NePasPrelettrer = tblHI->RecordCount <= 2;
//          while (!tblHI->IsEmpty())
          while (!tblHI->Eof)
            {
              tblHI->Edit();
              if (NePasPrelettrer || (AutoIDLigneASupprimer == tblHIAutoID->AsInteger))
                tblHI->Delettrer();
              else
              {
                if (HI_FlagLettrage->AsInteger == HIFLAG_LETTRAGE_PRELETTRE)
                {
                  tblHI->Next();
                  continue;
                }
                else
                  tblHI->Prelettrer(Prelettrage);
              }
              tblHI->Post();
            }
        }
        break;
      case HIAD_DELETTRER_LE_TOUT:
        {
          AnsiString Lettre,strCompte;
          FlagLettrage = (enum HIFlagLettrage)((TIntegerField *)FieldByName(strfHI_FlagLettrage))->AsInteger;
          strCompte = FieldByName(strfHI_Compte)->AsString;
          Lettre = HI_Lettrage->AsString;
          tblHI = CreerTableLettrage(0,0,0,0);
          tblHI->FiltrerLettrageRange(strCompte,Lettre,FlagLettrage);
          tblHI->First();
          while (!tblHI->IsEmpty())
            {
              tblHI->Edit();
              tblHI->Delettrer();
              tblHI->Post();
            }
        }
        break;
      default:
        ASSERT(eActionDelettrage == HIAD_DELETTRER_LA_LIGNE);
        ASSERT(State == dsEdit);

        FieldByName(strfHI_FlagLettrage)->AsInteger = HIFLAG_LETTRAGE_NON_LETTRE;
        HI_Lettrage->Clear();
        SetLettrageEstModifie(true);
    }
    }
  catch (Exception &e)
    {
      delete tblHI;
      tblHI = 0;
      throw EUser(TAGL,e);
    }
  delete tblHI;
  tblHI = 0;
} /* TTableHI::Delettrer() */




/*
  Cette fonction passe un pré-lettrage équilibré en lettrage en faisant attention au lettrage
  N + 1.
*/
void __fastcall TTableHI::LettrerPrelettrageEquilibre(const AnsiString &strCompte,const AnsiString &Prelettre,const AnsiString &Lettre, bool bCreateFilter /* = true */)
{
  bool Np1;
  TTableHI *tblHI;
  TDateTimeField *Date;
  TCurrencyField *Montant;
  TBooleanField *EstCrediteur;
  Currency Solde;
  Np1 = false;
  try
    {
      if (bCreateFilter)
        tblHI = CreerTableLettrage(0,0,0,&Date);
      else
        {
          tblHI = this;
          Date = (TDateTimeField *)FieldByName(strfHI_DateImputation);
        }
      Montant = (TCurrencyField *)tblHI->FieldByName(strfHI_Montant);
      EstCrediteur = (TBooleanField *)tblHI->FieldByName(strfHI_EstCrediteur);

      tblHI->FiltrerLettrageRange(strCompte,Prelettre,HIFLAG_LETTRAGE_PRELETTRE);
      tblHI->First();
      while (!tblHI->Eof)
        {
          Np1 |= (Date->AsDateTime > cm_DateFinExercice);
          Solde += (EstCrediteur->AsBoolean ? Montant->AsCurrency : -Montant->AsCurrency);
          tblHI->Next();
        }
       if (Solde != 0.0)
         EICThrowInvalidArgument(TAG(330));
      try
        {
          tblHI->First();
          while (!tblHI->IsEmpty())
            {
              tblHI->Edit();
              tblHI->Lettrer(Lettre,Np1);
              tblHI->Post();
            }
        }
      catch(Exception &e)
        {
          if (bCreateFilter)
            delete tblHI;
          tblHI = 0;
          throw EUser(TAG(331),e);
        }
      if (bCreateFilter)
        delete tblHI;
      tblHI = 0;
    }
  catch(Exception &e)
    {
      if (bCreateFilter)
        delete tblHI;
      tblHI = 0;
      throw EUser(TAG(332),e);
    }
}



void __fastcall TTableHI::LettrerPrelettrageEquilibreQuick( const AnsiString &strLettre, const TList *pListeRecNo)
{
  Currency   curSolde;
  AnsiString strCompte;
  AnsiString strPrelettre;
  bool       bNp1 = false;
  TStringField   *pfldCompte   = ( TStringField *)FieldByName( strfHI_Compte);
  TStringField   *pfldLettrage = ( TStringField *)FieldByName( strfHI_Lettrage);
  TDateTimeField *pfldDateImputation = ( TDateTimeField *)FieldByName( strfHI_DateImputation);
  TCurrencyField *pfldMontant        = ( TCurrencyField *)FieldByName( strfHI_Montant);
  TBooleanField  *pfldEstCrediteur   = ( TBooleanField  *)FieldByName( strfHI_EstCrediteur);
  bool bTransaction = pListeRecNo->Count < 255;
  try {
    // Vérifie la cohérence du lettrage à faire
    for( int i=0; i<pListeRecNo->Count; i++) {
        RecNo = (int)((TList *)pListeRecNo)->Items[i]; // On se place sur la ligne à lettrer
        if ( i==0) {
          // Sur la première ligne, on récupère les informations communes à toutes les lignes
          // afin de pouvoir vérifier la cohérence du lettrage
          strCompte    = pfldCompte  ->AsString;
          strPrelettre = pfldLettrage->AsString;
        } else {
          // Vérifie la cohérence de la ligne
          if ( pfldCompte  ->AsString!=strCompte   ) EICThrowInvalidArgument( TAG( 335));
          if ( pfldLettrage->AsString!=strPrelettre) EICThrowInvalidArgument( TAG( 336));
        }
        // Positionne un flag si on effectue un lettrage à cheval entre N et N+1
        bNp1 |= ( pfldDateImputation->AsDateTime > cm_DateFinExercice);
        // Calcule du solde du lettrage
        curSolde += ( pfldEstCrediteur->AsBoolean ? -pfldMontant->AsCurrency : pfldMontant->AsCurrency);
    }
    // Le solde est-il bien nul
    if ( curSolde!=0) EICThrowInvalidArgument( TAG( 337));

    // On va pouvoir lettrer car tout est correct
    try {
      Database->TransIsolation = tiDirtyRead;  // Commence une transaction
      if (bTransaction)
        Database->StartTransaction();
      for( int i=0; i<pListeRecNo->Count; i++) {
        RecNo = (int)((TList *)pListeRecNo)->Items[i]; // On se place sur la ligne à lettrer
        Edit(); Lettrer( strLettre, bNp1); Post();
      }
      if (bTransaction)
        Database->Commit();
    } catch ( Exception &e) {
      if (bTransaction)
        Database->Rollback(); // Annulation des modifications apportées
      throw EUser( TAG( 338), e);
    }

  } catch ( Exception &e) {
    throw EUser( TAG( 339), e);
  }
}



 /******************************************************************************\
 ************* TTableHI::PrelettrageSuivant() ***********************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction donne le pré-lettrage suivant pour un compte donné.        *
 *                                                                              *
 *    Paramètres :                                                              *
 *      strCompte : Compte                                                      *
 *                                                                              *
 \******************************************************************************/
AnsiString __fastcall TTableHI::PrelettrageSuivant(const AnsiString &strCompte)
{
  TTableHI *tblHI;
  TStringField *fCompte,*fLettre;
  TIntegerField *fFlagLettrage;
  AnsiString Lettre;
  try
    {
      tblHI = CreerTableLettrage(&fCompte,&fFlagLettrage,&fLettre,0);
      tblHI->SetRangeStart();
      fCompte->AsString = strCompte;
      fFlagLettrage->AsInteger = HIFLAG_LETTRAGE_PRELETTRE;
      fLettre->AsString = STR_CARACTERE_PRELETTRAGE STR_PREMIERE_LETTRE;
      tblHI->SetRangeEnd();
      fCompte->AsString = strCompte;
      fFlagLettrage->AsInteger = HIFLAG_LETTRAGE_PRELETTRE;
      fLettre->AsString = STR_CARACTERE_PRELETTRAGE "ZZZZ";
      tblHI->ApplyRange();
      if (tblHI->IsEmpty())
        Lettre = STR_CARACTERE_PRELETTRAGE STR_PREMIERE_LETTRE;
      else
        {
          tblHI->Last();
          Lettre = fLettre->AsString;
          IncLettre(Lettre);
        }
    }
  catch(Exception &e)
    {
      delete tblHI;
      tblHI = 0;
      throw EUser(TAGL,e);
    }
  delete tblHI;
  tblHI = 0;
  return Lettre;
} /* TTableHI::PrelettrageSuivant() */




 /******************************************************************************\
 ************* TTableHI::LettrageSuivant() **************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction donne le lettrage suivant pour un compte donné.            *
 *                                                                              *
 *    Paramètres :                                                              *
 *      strCompte : Compte                                                      *
 *                                                                              *
 \******************************************************************************/
AnsiString __fastcall TTableHI::LettrageSuivant(const AnsiString &strCompte)
{
  TTableHI *tblHI;
  TStringField *fCompte,*fLettre;
  TIntegerField *fFlagLettrage;
  AnsiString Lettre1,Lettre2;
  try
    {
      tblHI = CreerTableLettrage(&fCompte,&fFlagLettrage,&fLettre,0);
      tblHI->SetRangeStart();                    //Recherche de la première lettre dans N
      fCompte->AsString = strCompte;
      fFlagLettrage->AsInteger = HIFLAG_LETTRAGE_LETTRE_EIC;
      fLettre->AsString = STR_PREMIERE_LETTRE;
      tblHI->SetRangeEnd();
      fCompte->AsString = strCompte;
      fFlagLettrage->AsInteger = HIFLAG_LETTRAGE_LETTRE_EIC;
      fLettre->AsString = "ZZZZ";
      tblHI->ApplyRange();
      if (tblHI->IsEmpty())
        Lettre1 = STR_PREMIERE_LETTRE;
      else
        {
          tblHI->Last();
          Lettre1 = fLettre->AsString;
          IncLettre(Lettre1);
        }
      tblHI->SetRangeStart();                    //Recherche de la première lettre dans N+1
      fCompte->AsString = strCompte;
      fFlagLettrage->AsInteger = HIFLAG_LETTRAGE_LETTRE_NP1;
      fLettre->AsString = STR_PREMIERE_LETTRE;
      tblHI->SetRangeEnd();
      fCompte->AsString = strCompte;
      fFlagLettrage->AsInteger = HIFLAG_LETTRAGE_LETTRE_NP1;
      fLettre->AsString = "ZZZZ";
      tblHI->ApplyRange();
      if (tblHI->IsEmpty())
        Lettre2 = STR_PREMIERE_LETTRE;
      else
        {
          tblHI->Last();
          Lettre2 = fLettre->AsString;
          IncLettre(Lettre2);
        }
      if (Lettre2 > Lettre1)
        Lettre1 = Lettre2;                       //On prend la plus grande lettre
    }
  catch(Exception &e)
    {
      delete tblHI;
      tblHI = 0;
      throw EUser(TAGL,e);
    }
  delete tblHI;
  tblHI = 0;
  return Lettre1;
} /* TTableHI::LettrageSuivant() */




 /******************************************************************************\
 ************* TTableHI::IncLettre() ********************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction donne la lettre suivante.                                  *
 *    Le lettrage retenu est A,AA,AB,AC,...,AZ,B,BA,BB,...,ZZ.                  *
 *                                                                              *
 *    Paramètres :                                                              *
 *      strLettre : Une lettre de lettrage.                                     *
 *                                                                              *
 \******************************************************************************/
void __fastcall TTableHI::IncLettre(AnsiString &strLettre)
{
  int NoLettre;
  AnsiString NouvelleLettre;

  ASSERT(!strLettre.IsEmpty());

  if (strLettre[1] == CARACTERE_PRELETTRAGE)
    {//C'est un prélettrage
      NouvelleLettre = strLettre.SubString(2,3); //On élimine le "#"
      IncLettre(NouvelleLettre);
      strLettre = AnsiString(STR_CARACTERE_PRELETTRAGE) + NouvelleLettre;      //On remet le "#"
    }
  else
    {//C'est un lettrage
      if (strLettre.Length() == 1)
        NoLettre = 27 * ((int)(char(strLettre[1])) - 65);
      else
        NoLettre = int(strLettre[2]) - 64 + 27 * (int(strLettre[1]) - 65);
      NoLettre++;
      if (NoLettre % 27)
        NouvelleLettre = (AnsiString(char(NoLettre / 27 + 65)) + char(NoLettre % 27 + 64));
      else
        NouvelleLettre  = AnsiString(char(NoLettre / 27 + 65));
      if (NouvelleLettre > STR_DERNIERE_LETTRE)
        strLettre = STR_PREMIERE_LETTRE;             //On reboucle sur "A"
      else
        strLettre = NouvelleLettre;
    }
}




class LettrageCourant
{
public:
  AnsiString Compte,Lettre;
  __fastcall LettrageCourant()
    {
    }
  __fastcall LettrageCourant(const LettrageCourant &lc)
    {
      Compte = lc.Compte;
      Lettre = lc.Lettre;
    }
  bool __fastcall operator ==(const LettrageCourant &lc) const
    {
      return (Compte == lc.Compte) && (Lettre == lc.Lettre);
    }
  bool __fastcall operator <(const LettrageCourant &lc) const
    {
      return (Compte + "\\" + Lettre) < (lc.Compte + "\\" + lc.Lettre);
    }
};
typedef map<LettrageCourant,AnsiString> LettrageReclasse;
typedef LettrageReclasse::iterator LettrageReclasseIterator;
bool __fastcall TTableHI::ReclasserLettrages(const AnsiString &ComptesAReclasser,CBarre *pBarre)
{
  TStringField *tblHICompte,*tblHILettrage;
  TStringList *ListeComptesAReclasser = NULL;
  AnsiString Compte,Lettre;
  LettrageCourant Lettrage;
  LettrageReclasse Lettrages,Prelettrages,*l;
  LettrageReclasseIterator LettrageIT;
  CBarre Barre;
  try
    {
      ASSERT(Active);

      if (!pBarre)
        {
          Barre.Messages = "Reclassement des lettrages";
          Barre.Titre = "Reclassement";
          Barre.Open();
          pBarre = &Barre;
        }
      First();
      if (!Eof)
        {
          if (!ComptesAReclasser.IsEmpty())
            {
              ListeComptesAReclasser = new TStringList();
              ListeComptesAReclasser->CommaText = ComptesAReclasser;
            }
          IndexName = sziHI_LettrageDate;
          tblHICompte = (TStringField *)FieldByName(strfHI_Compte);
          tblHILettrage = (TStringField *)FieldByName(strfHI_Lettrage);
          pBarre->Max = RecordCount * 2;
          SCAN_TABLE(this)
            {//On cherche tous les lettrages et pré-lettrages dans l'historique (des comptes demandés)
              if ((EstLettreEIC || EstPrelettre) && (!ListeComptesAReclasser || (ListeComptesAReclasser->IndexOf(tblHICompte->AsString) != -1)))
                {
                  Lettrage.Compte = tblHICompte->AsString;
                  Lettrage.Lettre = tblHILettrage->AsString;
                  l = EstPrelettre ? &Prelettrages : &Lettrages;
                  LettrageIT = l->find(Lettrage);
                  if (LettrageIT == l->end())
                    l->insert(LettrageReclasse::value_type(Lettrage,EmptyStr));
                }
              (*pBarre)++;
            }
          IndexName = EmptyStr;
          for (LettrageIT = Lettrages.begin();LettrageIT != Lettrages.end();LettrageIT++)
            {//On crée une table de correspondance pour tous les lettrages
              if (Compte != LettrageIT->first.Compte)
                {
                  Lettre = STR_PREMIERE_LETTRE;
                  Compte = LettrageIT->first.Compte;
                }
              LettrageIT->second = Lettre;
              IncLettre(Lettre);
            }
          Compte = EmptyStr;
          for (LettrageIT = Prelettrages.begin();LettrageIT != Prelettrages.end();LettrageIT++)
            {//On crée une table de correspondance pour tous les pré-lettrages
              if (Compte != LettrageIT->first.Compte)
                {
                  Lettre = STR_CARACTERE_PRELETTRAGE STR_PREMIERE_LETTRE;
                  Compte = LettrageIT->first.Compte;
                }
              LettrageIT->second = Lettre;
              IncLettre(Lettre);
            }
          SCAN_TABLE(this)
            {//On réaffecte tous les lettrages et pré-lettrages reclassés
              if ((EstLettreEIC || EstPrelettre) && (!ListeComptesAReclasser || (ListeComptesAReclasser->IndexOf(tblHICompte->AsString) != -1)))
                {
                  Lettrage.Compte = tblHICompte->AsString;
                  Lettrage.Lettre = tblHILettrage->AsString;
                  l = EstPrelettre ? &Prelettrages : &Lettrages;
                  LettrageIT = l->find(Lettrage);

                  ASSERT(LettrageIT != l->end());

                  if (LettrageIT->first.Lettre != LettrageIT->second)
                    {
                      Edit();
                      tblHILettrage->AsString = LettrageIT->second;
                      Post();
                    }
                }
              (*pBarre)++;
            }
          delete ListeComptesAReclasser;
          ListeComptesAReclasser = NULL;
        }
      return true;
    }
  catch (Exception &e)
    {
      delete ListeComptesAReclasser;
      EICDisplayException(TAGL,e);
      return false;
    }
}



 /******************************************************************************\
 ************* TTableHI::DrawLettrage() *****************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction dessine le lettrage sur une grille.                        *
 *                                                                              *
 *    Paramètres :                                                              *
 *      Sender : Grille où dessiner le lettrage                                 *
 *      Rect : Rectangle où dessiner le lettrage                                *
 *      State : Etat de la cellule (sélectionnée ou pas)                        *
 *      Lettrage : Valeur du lettrage                                           *
 *      FlagLettrage : Type de lettrage (Importé, Lettré, Prélettré, Non Lettré)*
 *                                                                              *
 \******************************************************************************/
void __fastcall TTableHI::DrawLettrage(TDBGrid *Sender,const TRect &Rect,int DataCol,TColumn* Column,TGridDrawState State,HIFlagLettrage FlagLettrage)
{
  Sender->Canvas->FillRect(Rect);
  if (!State.Contains(gdSelected))
    switch (FlagLettrage)
      {
        case HIFLAG_LETTRAGE_LETTRE_IMPORTE:
        case HIFLAG_LETTRAGE_LETTRE_IMPORTE_NP1:
          Sender->Canvas->Font->Color = COULEUR_LETTRAGE_IMPORTE;
          break;
        case HIFLAG_LETTRAGE_LETTRE_EIC:
          Sender->Canvas->Font->Color = COULEUR_LETTRAGE;
          break;
        case HIFLAG_LETTRAGE_LETTRE_NP1:
          Sender->Canvas->Font->Color = COULEUR_LETTRAGE_NP1;
          break;
        case HIFLAG_LETTRAGE_PRELETTRE:
          Sender->Canvas->Font->Color = COULEUR_PRELETTRAGE;
          break;
        default:
          return;
      }
  if ((FlagLettrage == HIFLAG_LETTRAGE_LETTRE_NP1) || (FlagLettrage == HIFLAG_LETTRAGE_LETTRE_IMPORTE_NP1))
    {//On rajoute une étoile devant la lettre
      ((TDBGrid *)Sender)->Canvas->TextOut(Rect.Left + 2,Rect.Top + 2,AnsiString("*") + ((TStringField *)Column->Field)->AsString);
      return;
    }
  Sender->DefaultDrawColumnCell(Rect,DataCol,Column,State);
} /* TTableHI::DrawLettrage() */




/******************************************************************************\
************* TTableHI::FiltrerLettrage() **************************************
********************************************************************************
*                                                                              *
*    Cette fonction dessine le lettrage sur une grille.                        *
*                                                                              *
*    Paramètres :                                                              *
*      TypeFiltre : Type de filtre à appliquer                                 *
*      Lettre : Lettre servant à filtrer                                       *
*                                                                              *
\******************************************************************************/
void __fastcall TTableHI::FiltrerLettrage(HIFiltreLettrage TypeFiltre,const AnsiString &Lettre)
{
  switch (TypeFiltre)
    {
      case HIFL_TOUT:                            //Tout (Pas de Filter mais il reste le OnFilterRecord)
        ASSERT(Lettre == EmptyStr);

        Filter = EmptyStr;
        break;
      case HIFL_PRELETTRE_ET_NON_LETTRE:         //Que le non lettré et le pré-lettré
        ASSERT(Lettre == EmptyStr);

        Filter = szfHI_FlagLettrage ">'" STR_HIFLAG_LETTRAGE_LETTRE_NP1 "'";
        break;
      case HIFL_TOUT_SAUF_PRELETTRAGE_EN_COURS:  //Tout sauf le pré-lettrage en cours
        ASSERT(Lettre != EmptyStr);

        Filter = szfHI_Lettrage "<>'" + Lettre + "' or "
                 szfHI_FlagLettrage "<>'" STR_HIFLAG_LETTRAGE_PRELETTRE "'";
        break;
      case HIFL_NI_LETTRAGE_NI_PRELETTRAGE_EN_COURS:       //Ni les lettrés ni le pré-lettrage en cours
        ASSERT(Lettre != EmptyStr);

        Filter = szfHI_FlagLettrage ">'" STR_HIFLAG_LETTRAGE_LETTRE_NP1 "' and ("
                 szfHI_Lettrage "<>'" + Lettre + "' or "
                 szfHI_FlagLettrage "<>'" STR_HIFLAG_LETTRAGE_PRELETTRE "')";
        break;
      case HIFL_QUE_PRELETTRAGE_EN_COURS:        //Que le lettrage en cours
        ASSERT(Lettre != EmptyStr);

        Filter = szfHI_Lettrage "='" + Lettre + "' and " szfHI_FlagLettrage "='" STR_HIFLAG_LETTRAGE_PRELETTRE "'";
        break;
      case HIFL_LETTRAGE_IMPORTE_ET_LETTRE:
        ASSERT(Lettre != EmptyStr);

        Filter = szfHI_Lettrage "='" + Lettre + "' and " szfHI_FlagLettrage "='" STR_HIFLAG_LETTRAGE_LETTRE_IMPORTE "'";
        break;
      case HIFL_PRELETTRAGE_ET_LETTRE:
        ASSERT(Lettre != EmptyStr);

        Filter = szfHI_Lettrage "='" + Lettre + "' and " szfHI_FlagLettrage "='" STR_HIFLAG_LETTRAGE_PRELETTRE "'";
        break;
      default:                                   //Rien (Filtre qui ne laisse rien passer)
        ASSERT(TypeFiltre == HIFL_RIEN);
        ASSERT(Lettre == EmptyStr);

        Filter = szfHI_FlagLettrage "='0'";
    }
  Filtered = true;
} /* TTableHI::FiltrerLettrage() */




void __fastcall TTableHI::FiltrerLettrage(const AnsiString &Compte,const AnsiString &Lettre,enum HIFlagLettrage TypeLettrage)
{
  Filter = szfHI_Compte "='" + Compte + "' and " + szfHI_Lettrage "='" + Lettre + "' and " szfHI_FlagLettrage "='" + TypeLettrage + "'";
  Filtered = true;
}



void __fastcall TTableHI::FiltrerLettrageRange(const AnsiString &Compte,const AnsiString &Lettre,enum HIFlagLettrage TypeLettrage)
{
  ASSERT(IndexName == "idxLettrageDate");

  SetRangeStart();
  KeyFieldCount = 3;
  FieldByName(szfHI_Compte)->AsString = Compte;
  FieldByName(szfHI_FlagLettrage)->AsInteger = TypeLettrage;
  FieldByName(szfHI_Lettrage)->AsString = Lettre;
  SetRangeEnd();
  KeyFieldCount = 3;
  FieldByName(szfHI_Compte)->AsString = Compte;
  FieldByName(szfHI_FlagLettrage)->AsInteger = TypeLettrage;     
  FieldByName(szfHI_Lettrage)->AsString = Lettre;
  ApplyRange();
}



TTableHI* __fastcall TTableHI::CreerTableLettrage(TStringField **fCompte,TIntegerField **fFlagLettrage,TStringField **fLettrage,TDateTimeField **fDateImputation)
{
  TTableHI *tblHI;
  try
    {
      tblHI = 0;
      tblHI = new TTableHI(this);
      tblHI->IndexName = "idxLettrageDate";
      tblHI->Open();
      if (fCompte)
        *fCompte = (TStringField *)tblHI->FieldByName(strfHI_Compte);
      if (fFlagLettrage)
        *fFlagLettrage = (TIntegerField *)tblHI->FieldByName(strfHI_FlagLettrage);
      if (fLettrage)
        *fLettrage = (TStringField *)tblHI->FieldByName(strfHI_Lettrage);
      if (fDateImputation)
        *fDateImputation = (TDateTimeField *)tblHI->FieldByName(strfHI_DateImputation);
    }
  catch (Exception &e)
    {
      throw EUser(TAGL,e);
    }
  return tblHI;
}



bool __fastcall TTableHI::LettrageTotalementDans(const TDateTime &DateDeb,const TDateTime &DateFin, const AnsiString &Compte,const AnsiString &Lettre,enum HIFlagLettrage TypeLettrage)
{
  bool Resultat;
  TTableHI *tblHI;
  TDateTimeField *fDateImputation;
  try
    {
      tblHI = CreerTableLettrage(0,0,0,&fDateImputation);
      tblHI->FiltrerLettrageRange(Compte,Lettre,TypeLettrage);

      ASSERT(!tblHI->IsEmpty());       //Le lettrage doit exister

      tblHI->First();
      Resultat = fDateImputation->AsDateTime >= DateDeb;   //La première date doit être >= à la date de début d'exercice
      tblHI->Last();
      Resultat = Resultat && (fDateImputation->AsDateTime <= DateFin);         //et la dernière date doit être <= à la date de fin d'exercice
    }
  catch(Exception &e)
    {
      delete tblHI;
      tblHI = 0;
      throw EUser(TAG(1001),e);
    }
  delete tblHI;
  tblHI = 0;
  return Resultat;
}


void __fastcall TTableHI::ChangeIDEcriture( int nCurID, int nNewID)
{
  ASSERT(Active);
  ASSERT(!Filtered);

  // Vérifie que l'ID d'écriture nouveau n'est pas déjà utilisé
  if ( Locate( strfHI_IDEcriture, nNewID, _loInsensitive)) ::EICThrowInvalidArgument( TAG( 100));
  // Recherche si l'ID d'écriture à remplacer existe
  if ( Locate( strfHI_IDEcriture, nCurID, _loInsensitive)) {
    // Remplace l'ID d'écriture
    TIntegerField *pfldIDEcriture = ( TIntegerField*)FieldByName( strfHI_IDEcriture);
    while( pfldIDEcriture->AsInteger==nCurID)
    {
      Edit();
      pfldIDEcriture->AsInteger = nNewID;
      Next();
    }
  }
}

bool __fastcall TTableHI::GetEstLignePointee()
{
  return !FieldByName( strfHI_DateEP)->IsNull;
}

bool __fastcall TTableHI::GetEstLigneValidee()
{
  return LIGNE_EST_VALIDEE( FieldByName( strfHI_Flags)->AsInteger);
}

bool __fastcall TTableHI::EstEcriturePointee( int nIDEcr)
{
  ASSERT( !Filtered);

  TIntegerField *pfldIDEcriture = ( TIntegerField*)FieldByName( strfHI_IDEcriture);
  bool           bLignePointee  = false;

  if( Locate( strfHI_IDEcriture, nIDEcr, _loNormal)) {
    do {
      bLignePointee |= EstLignePointee;
      Next();
    } while(( pfldIDEcriture->AsInteger==nIDEcr) && !Eof);
  }
  return bLignePointee;
}

bool __fastcall TTableHI::EstEcritureValidee( int nIDEcr)
{
  ASSERT( !Filtered);
  return ( Locate( strfHI_IDEcriture, nIDEcr, _loNormal) && EstLigneValidee);
}

void __fastcall TTableHI::InternalOpen()
{
  inherited::InternalOpen();

  if( m_nCountInstance++==0) {
    FLDDesc fldDesc[2];
    IDXDesc idxDesc;

    m_pTable = new CTable( ttDossier, "INC");

    INIT_PARADOX_FIELD_LONG( fldDesc, 0, "IDMaster");
    INIT_PARADOX_FIELD_LONG( fldDesc, 1, "IDInc"   );
    INIT_PARADOX_INDEX_PRIMAIRE_1( idxDesc);

    if( !ComponentState.Contains( csDesigning)) {
      ASSERT( m_pTable); // L'assert qui fait la différence NE PAS SUPPRIMER A VOS RISQUES ET PERILS
      m_pTable->CreateTable( false, 2, fldDesc, 1, &idxDesc);
      m_pTable->Open();

      m_pfldIDMaster = ( TIntegerField*)m_pTable->Fields->Fields[0];
      m_pfldIDInc    = ( TIntegerField*)m_pTable->Fields->Fields[1];

      if( !m_pTable->FindKey( ARRAYOFCONST(( m_nReviseur)))) {
        TQuery *qryRef = NULL;
        int     nRef   = 0;
        try {
          qryRef = new TQuery( NULL);
          qryRef->DatabaseName = DatabaseName;
          qryRef->SQL->Text    = "SELECT MAX(" szfHI_Reference ") FROM '" + TableName + "' WHERE(" szfHI_Reviseur "=" + IntToStr( m_nReviseur) + ")";
          qryRef->Open();
          nRef = qryRef->Fields->Fields[0]->AsInteger + 1;
          qryRef->Close();
          // Et vérifie qu'il n'existe pas une référence plus grande ds INVR$$H
          qryRef->SQL->Text    = "SELECT MAX(" szfHI_Reference ") FROM INVR$$H WHERE(" szfHI_Reviseur "=" + IntToStr( m_nReviseur) + ")";
          qryRef->Open();
          if( qryRef->Fields->Fields[0]->AsInteger>=nRef)
              nRef = qryRef->Fields->Fields[0]->AsInteger + 1;
          qryRef->Close();
        } catch( Exception &e) {
        }
        delete qryRef;

        m_pTable->Append();
        m_pfldIDMaster->AsInteger = m_nReviseur;
        m_pfldIDInc   ->AsInteger = nRef;
        m_pTable->Post();
      }
    }
  }
}

void __fastcall TTableHI::InternalClose()
{
  inherited::InternalClose();
  if( --m_nCountInstance==0) {
    m_pTable->Close();
    delete m_pTable;
    m_pTable       = NULL;
    m_pfldIDMaster = NULL;
    m_pfldIDInc    = NULL;
  }
}

int __fastcall TTableHI::GetReferenceSuivante()
{
  ASSERT( m_pTable->Active);
  ASSERT( m_pfldIDMaster->AsInteger==m_nReviseur);

  int nRef = m_pfldIDInc->AsInteger;
  m_pTable->Edit();
  m_pfldIDInc->AsInteger = nRef + 1;
  m_pTable->Post();
  return nRef;
}



void __fastcall TTableHI::ValidationEcriture( int nIDEcr)
{
  FilterID       Filtre( FID_NUL);
  TIntegerField *pfldFlags = ( TIntegerField*)FieldByName( strfHI_Flags);

  DisableControls();
  PushFilter( Filtre, strfHI_IDEcriture + "=" + IntToStr( nIDEcr));
  SCAN_TABLE( this) {
    Edit();
    pfldFlags->AsInteger = pfldFlags->AsInteger | HIFLAGS_VALIDEE;
    Post();
  }
  PopFilter( Filtre);
  EnableControls();
}

void __fastcall TTableHI::SetCodeReviseur( int nCode)
{
  if( m_nCountInstance!=0) EICThrowInvalidArgument( TAG( 531));
  m_nReviseur = nCode;
}

 //****************//
 // CPropsEcriture //
 //****************//////////////////////////////////////////////////////////////
 //                                                                            //
 //    Cette classe permet de gérer, conjointement avec un Historique, les     //
 // propriétés d'une écriture comptable.                                       //
 ////////////////////////////////////////////////////////////////////////////////
 TTableHI& __fastcall operator<<(TTableHI& tblHI, const CPropsEcriture& pe)
 {
  TFloatField* pfldTauxChange;
  TDateTimeField* pfldDateImputation;

  ASSERT(tblHI.Active && (tblHI.State == dsEdit) || (tblHI.State == dsInsert));
  ASSERT(dynamic_cast<TDateTimeField*>(tblHI.FieldByName(TTableHI::strfHI_DateImputation)));

  tblHI.FieldByName(TTableHI::strfHI_IDEcriture)->AsInteger = pe.m_nIDEcriture;
  tblHI.FieldByName(TTableHI::strfHI_Flags)->AsInteger = pe.m_eFlags;
  tblHI.FieldByName(TTableHI::strfHI_CodeJournal)->AsString  = pe.m_strCodeJnl;
  tblHI.FieldByName(TTableHI::strfHI_CodeDevise)->AsInteger = pe.CodeDevise;
  pfldTauxChange = (TFloatField*)tblHI.FieldByName(TTableHI::strfHI_TauxChange);
  if(pe.EstDeviseEuroNat)
    pfldTauxChange->Clear();
  else
    pfldTauxChange->AsFloat = pe.TauxChangeDevise;
  pfldDateImputation = (TDateTimeField*)tblHI.FieldByName(TTableHI::strfHI_DateImputation);
  pfldDateImputation->AsDateTime = pe.m_dateImputation;
  return(tblHI);
 } /* operator<<() */

 CTable& __fastcall operator<<(CTable& tblHI2, const CPropsEcriture& pe)
 {
  ASSERT(tblHI2.Active && (tblHI2.State == dsEdit) || (tblHI2.State == dsInsert));
  tblHI2.FieldByName(TTableHI::strfHI_NaturePiece)->AsString = pe.m_strNaturePiece;
  tblHI2.FieldByName(TTableHI::strfHI_RAOIDLigne)->AsInteger = pe.m_eRAOIDLigne;
  tblHI2.FieldByName(TTableHI::strfHI_IDEcriturePart)->AsString = pe.m_IDEcriturePart;
  return(tblHI2);
 } /* operator<<() */



 /******************************************************************************\
 ************* CPropsEcriture::InitHIPieceFrom() ********************************
 ********************************************************************************
 *                                                                              *
 *    Cette procédure permet d'initialiser la pièce d'une ligne d'un historique.*
 *                                                                              *
 * Paramètres :                                                                 *
 *   ptblHI    : Historique dans lequel initialiser la pièce de l'enregistrement*
 *               courant (qui doit être en mode ajout ou modification).         *
 *   ptblHITmp : Table qui contient la ligne d'écriture temporaire de laquelle  *
 *               prendre la pièce pour la copier dans le HI à initialisaer. Si  *
 *               la pièce est constante sur l'écriture, ce paramètre est ignoré;*
 *               Si ce paramètre est nul et que la pièce n'est pas constante    *
 *               sur l'écriture, la fonction ne fait rien (dans ce cas, cela    *
 *               signifie que la pièce du HI doit être vide).                   *
 \******************************************************************************/
 void __fastcall CPropsEcriture::InitHIPieceFrom(TTableHI*    ptblHI,
                                                  TTableHITmp* ptblHITmp)
 const
 {
  ASSERT(ptblHI);
  ASSERT((ptblHI->State == dsInsert) || (ptblHI->State == dsEdit));

  // Si la pièce est constante sur l'écriture, elle doit aussi figurer dans le HITmp
  ASSERT(!m_bPieceConst || !ptblHITmp || (ptblHITmp->FieldByName(TTableHITmp::strfHITmp_Piece)->AsString == m_strPieceConst));


  if(m_bPieceConst || ptblHITmp)
  {
    ptblHI->FieldByName(TTableHI::strfHI_Piece)->AsString = m_bPieceConst ? m_strPieceConst : ptblHITmp->FieldByName(TTableHITmp::strfHITmp_Piece)->AsString;
  }
  else
    ASSERT(ptblHI->FieldByName(TTableHI::strfHI_Piece)->IsNull);
 }



 __fastcall CPropsEcriture::CPropsEcriture(int                nIDEcriture,
                                            TTableHI::THIFlags eFlags,
                                            const CDevise&     devEcriture,
                                            const AnsiString&  strCodeJnl,
                                            const TDateTime&   dateImputation,
                                            bool               bPieceConst,
                                            const AnsiString&  strPieceConst,
                                            const AnsiString&  strNaturePiece /* = EmptyStr */,
                                            unsigned int       eRAOIDLigne,
                                            const AnsiString &strIDEcriturePart)
 : m_nIDEcriture(nIDEcriture), m_eFlags(eFlags),
   m_devEcriture(devEcriture),
   m_eCodeDevise(devEcriture.Code), m_bDeviseEuroNat(devEcriture.EstDeviseEuro), m_dblTxChgDevise(devEcriture.Taux),
   m_strCodeJnl(strCodeJnl), m_dateImputation(dateImputation),
   m_bPieceConst(bPieceConst), m_strPieceConst(strPieceConst), m_strNaturePiece(strNaturePiece),
   m_eRAOIDLigne(eRAOIDLigne),m_IDEcriturePart(strIDEcriturePart)
 {
  ASSERT(nIDEcriture != IdEcritureNouvelle);
  ASSERT((eFlags == TTableHI::HIFLAGS_IMPORTEE)         ||
          (eFlags == TTableHI::HIFLAGS_EST_ANNULEE) ||
          (eFlags == TTableHI::HIFLAGS_NORMALE)         ||
          (eFlags == TTableHI::HIFLAGS_NORMALE_ANNULEE) ||
          (eFlags == (TTableHI::HIFLAGS_NORMALE         | TTableHI::HIFLAGS_A_CONTREPASSER)) ||
          (eFlags == (TTableHI::HIFLAGS_NORMALE_ANNULEE | TTableHI::HIFLAGS_A_CONTREPASSER)));
  ASSERT(!strCodeJnl.IsEmpty() && (strCodeJnl.Length() <= 4));
  ASSERT((dateImputation >= TDateTime(1980, 1, 1)) && (dateImputation <= TDateTime(2050, 12, 31)));
  ASSERT(m_eCodeDevise != CODE_DEVISE_DEFAUT);
  ASSERT(DeviseEstValide(dateImputation, devEcriture, AnsiString()));
 }




 //*************//
 // TTableHITmp //
 //*************/////////////////////////////////////////////////////////////////
 //                                                                            //
 //    Cette classe permet de gérer une table "Historique temporaire" à        //
 // utiliser pour la création/modification d'écritures dans un Historique.     //
 ////////////////////////////////////////////////////////////////////////////////
 /*----------------------------------------------------------------------------*\
 ------------- TTableHITmp::ContientLaLigneDOrigine() ---------------------------
 --------------------------------------------------------------------------------
 - L'ENREGISTREMENT COURANT N'EST PAS MODIFIE -----------------------------------
 --------------------------------------------------------------------------------
 -                                                                              -
 -    Cette fonction permet de savoir si la table contient une certaine ligne   -
 - issue d'une écriture d'un HI et si cette ligne est la ligne courante.        -
 -                                                                              -
 - Paramètres :                                                                 -
 -   nIDLigneOrigine     : ID de la ligne d'origine à rechercher.               -
 -   bEstLaLigneCourante : Retourne TRUE si la ligne à rechercher est la ligne  -
 -                         courante (et a donc été trouvée); FALSE sinon.       -
 -                                                                              -
 - Retour :                                                                     -
 -   TRUE si la ligne d'origine a été trouvée; FALSE sinon.                     -
 \*----------------------------------------------------------------------------*/
 bool __fastcall TTableHITmp::ContientLaLigneDOrigine(int   nIDLigneOrigine,
                                                       bool& bEstLaLigneCourante)
 {
  TIntegerField* pfldIDLigne;
  bool           bFound;

  ASSERT(nIDLigneOrigine != 0); // Car cet ID est celui utilisé pour une nouvelle ligne
  ASSERT(State == dsBrowse);


  try {
    pfldIDLigne = (TIntegerField*)FieldByName(strfHITmp_IDLigne);


    /////////////////////////////////////
    // Recherche de la ligne d'origine //
    /////////////////////////////////////
    if(pfldIDLigne->AsInteger == nIDLigneOrigine)
    { // => Ligne d'origine trouvée en tant que ligne courante
      bEstLaLigneCourante = true;
      bFound              = true;
    }
    else
    { // => Ligne d'origine non trouvée en tant que ligne courante
      bEstLaLigneCourante = false;

      AnsiString strBmkCurrent(Bookmark); // Ligne courante

      if(Locate(strfHITmp_IDLigne, nIDLigneOrigine, _loNormal))
      { // Ligne d'origine trouvée en tant que ligne différente de la ligne courante
        bFound   = true;
        Bookmark = strBmkCurrent;
      }
      else
      { // Ligne d'origine non trouvée
        ASSERT(Bookmark == strBmkCurrent);
        bFound = false;
      }
    }
  } catch(Exception& e) {
    throw EUser(TAG(340), e);
  }

  return(bFound);
 } /* TTableHITmp::ContientLaLigneDOrigine() */



 /******************************************************************************\
 ************* TTableHITmp::CopyEcritureFrom() **********************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet d'initialiser la table avec les lignes détail d'une *
 * écriture donnée et retourne ses principales caractéristiques (la table est   *
 * initialisée avec les montants d'origine de l'écriture i.e. dans la devise de *
 * saisie).                                                                     *
 *                                                                              *
 * Paramètres :                                                                 *
 *   nIDEcriture    : ID de l'écriture à recopier dans la table.                *
 *   ptblHI         : HI duquel extraire l'écriture (ne doit pas être filtré).  *
 *   devEcriture    : Retourne      la devise        de l'écriture copiée.      *
 *   dateImputation :    "     la date d'imputation  "       "        "         *
 *   strCodeJnl     :    "       le code journal     "       "        "         *
 *   bPieceConst    :    "       TRUE si la pièce    "       "        "   est constante
 *   strPieceConst  :    "        le code pièce      "       "        "   (non modifié si bPieceConstante retourne false)
 *   strNaturePiece :    "     la nature de la pièce "       "        "         *
 *   bAnnulee       :    "     TRUE si écriture copiée est complètement annulée.*
 *   pbarre         : Barre de progression à utiliser (NULL = aucune)           *
 *                                                                              *
 * Retour :                                                                     *
 *   TRUE si l'écriture recopiée ne contient que des lignes modifiables par     *
 * l'utilisateur; FALSE sinon (i.e. l'écriture ne contient que des lignes       *
 * annulées - et n'est donc pas modifiable - ou bien n'est pas modifiable - cas *
 * d'une écriture d'"A Nouveaux").                                              *
 *                                                                              *
 * Notes : - Le filtre du HI source est modifié par cette procédure.            *
 *         - Les lignes de l'écriture marquées comme "modifiées" ne sont pas    *
 *           recopiées dans la table.                                           *
 \******************************************************************************/
 bool __fastcall TTableHITmp::CopyEcritureFrom( int                nIDEcriture,    // ID de l'écriture à recopier
                                                TTableHI*          ptblHI,         // HI dans lequel prendre l'écriture
                                                CTable*            ptblHI2,         // HI dans lequel prendre l'écriture
                                                CDevise&           devEcriture,    // Retourne la devise de l'écriture
                                                TDateTime&         dateImputation, //    "     la date d'imputation de l'écriture
                                                AnsiString&        strCodeJnl,     //    "     le code journal de l'écritur
                                                bool&              bPieceConst,    //    "     TRUE si la pièce de l'écriture est constante sur toutes ses lignes
                                                AnsiString&        strPieceConst,  //    "     la pièce constante de l'écriture (à ignorer si bPieceConstante == false)
                                                AnsiString&        strNaturePiece, //    "     la nature de la pièce de l'écriture
                                                bool&              bAnnulee,       //    "     TRUE si l'écriture est complètement annulée
                                                TEcartChgEcriture *pEcartCh,
                                                AnsiString &IDEcriturePart,
                                                CBarre*            pbarre)
 {
  bool       bModifiable;         // TRUE si l'utilisateur peut modifier la copie de l'écriture
  bool       bPieceConstante;     // TRUE si la pièce est constante sur l'écriture
  AnsiString strPieceConstante;   // Pièce constante de l'écriture
  bool       bEntierementAnnulee; // TRUE si toutes les lignes de l'écriture sont annulées
  int        uFlags;              // Drapeaux d'une ligne de l'écriture à copier
  FilterID   fidEcriture;         // ID du filtre (sur le HI source) de l'écriture à copier
  bool       bTesterPiece;
  AnsiString strMasterFields;
  TDataSource *ds = NULL;
  ASSERT(nIDEcriture != IdEcritureNouvelle);
  ASSERT(ptblHI);
  ASSERT(ptblHI->Active);
  ASSERT(!ptblHI->Filtered);
  ASSERT(ptblHI2);
  ASSERT(ptblHI2->Active);
  ASSERT(!ptblHI2->Filtered);
  #ifdef _DEBUG
    if (!ptblHI2->IsEmpty())
      ASSERT(ptblHI2->FieldByName(TTableHI::strfHI_AutoID)->AsInteger == ptblHI->FieldByName(TTableHI::strfHI_AutoID)->AsInteger);
  #endif

  bPieceConstante = true;
  fidEcriture     = FID_NUL;


  try {
    strMasterFields = ptblHI2->MasterFields;
    ds = ptblHI2->MasterSource;
    ptblHI2->MasterSource = NULL;
    ptblHI2->MasterFields = EmptyStr;

    ptblHI->DisableControls();
    EmptyTable();
    ptblHI->PushFilter(fidEcriture, szfHI_IDEcriture "=" + AnsiString(nIDEcriture));
    if(ptblHI->IsEmpty())
    { // Erreur: Ecriture source non trouvée dans le HI passé en paramètre
      EICThrowInvalidArgument(TAG(350));
    }
    if(pbarre)
      pbarre->Max = ptblHI->RecordCount;


    ////////////////////////////////////////////////
    // Lecture des caractéristiques de l'écriture //
    ////////////////////////////////////////////////
    // Ces caractéristiques sont lues d'après la 1ère ligne de l'écriture
    TDateTimeField* pDateImput;
    bool thlHI2Trouve = !ptblHI2->IsEmpty();

    pDateImput        = (TDateTimeField*)ptblHI->FieldByName(TTableHI::strfHI_DateImputation);
    dateImputation    = pDateImput->AsDateTime;
    strCodeJnl        = ptblHI->FieldByName(TTableHI::strfHI_CodeJournal)->AsString;
    strPieceConstante = ptblHI->FieldByName(TTableHI::strfHI_Piece)->AsString;
    if (thlHI2Trouve)
      {
        strNaturePiece = ptblHI2->FieldByName(TTableHI::strfHI_NaturePiece)->AsString;
        IDEcriturePart = ptblHI2->FieldByName(TTableHI::strfHI_IDEcriturePart)->AsString;
      }
    devEcriture       = CDevise((TCodeDev)ptblHI->FieldByName(TTableHI::strfHI_CodeDevise)->AsInteger,
                                 ptblHI->FieldByName(TTableHI::strfHI_TauxChange)->AsFloat);

    AnsiString strFldDst2(szfHITmp_RAOIDLigne     ";" szfHITmp_RAOData      ";" szfHITmp_Designation  ";"
                          szfHITmp_CodeTVA        ";" szfHITmp_TauxTVA      ";" szfHITmp_Banque       ";"
                          szfHITmp_Quantite       ";" szfHITmp_PieceExterne ";" szfHITmp_CodeAnalytik );

    AnsiString strFldSrc2(szfHI_RAOIDLigne      ";" szfHI_RAOData         ";" szfHI_Designation     ";"
                          szfHI_CodeTVA         ";" szfHI_TauxTVA         ";" szfHI_Banque          ";"
                          szfHI_Quantite        ";" szfHI_PieceExterne    ";" szfHI_CodeAnalytik );

    AnsiString strFldDst( szfHITmp_Compte       ";" szfHITmp_Piece        ";" szfHITmp_LibelleOperation ";" szfHITmp_IDLigne  ";"
                          szfHITmp_Lettrage     ";" szfHITmp_FlagLettrage ";" szfHITmp_DateEcheance ";" szfHITmp_ModePaiement ";"
                          szfHITmp_DateEP       ";" szfHITmp_IDImage);

    AnsiString strFldSrc( szfHI_Compte       ";" szfHI_Piece        ";" szfHI_LibelleOperation ";" szfHI_AutoID       ";"
                          szfHI_Lettrage     ";" szfHI_FlagLettrage ";" szfHI_DateEcheance ";"     szfHI_ModePaiement ";"
                          szfHI_DateEP       ";" szfHI_IDImage);
    TBooleanField*  pfldHITmpEstNouvelleLigne = (TBooleanField*) FieldByName(strfHITmp_EstNouvelleLigne);              ASSERT(pfldHITmpEstNouvelleLigne);
    TCurrencyField* pfldHITmpDebit            = (TCurrencyField*)FieldByName(strfHITmp_Debit);                         ASSERT(pfldHITmpDebit);
    TCurrencyField* pfldHITmpCredit           = (TCurrencyField*)FieldByName(strfHITmp_Credit);                        ASSERT(pfldHITmpCredit);
    TBooleanField  *pfldHITmpIDImageModifie   = (TBooleanField *)FieldByName(strfHITmp_IDImageModifie);                ASSERT(pfldHITmpIDImageModifie);
    TDateTimeField* pfldHITmpDateDebPeriode   = (TDateTimeField*)FindField(  strfHITmp_DateDebPeriode);
    TDateTimeField* pfldHITmpDateFinPeriode   = (TDateTimeField*)FindField(  strfHITmp_DateFinPeriode);
    TStringField*   pfldHIPiece               = (TStringField*)  ptblHI->FieldByName(TTableHI::strfHI_Piece);          ASSERT(pfldHIPiece);
    TBooleanField*  pfldHIEstCrediteur        = (TBooleanField*) ptblHI->FieldByName(TTableHI::strfHI_EstCrediteur);   ASSERT(pfldHIEstCrediteur);
    TCurrencyField* pfldHIMontantO            = (TCurrencyField*)ptblHI->FieldByName(TTableHI::strfHI_MontantOrigine); ASSERT(pfldHIMontantO);
    TIntegerField*  pfldHIFlags               = (TIntegerField*) ptblHI->FieldByName(TTableHI::strfHI_Flags);          ASSERT(pfldHIFlags);
    TIntegerField *tblHIAutoID = (TIntegerField *)ptblHI->FieldByName(TTableHI::strfHI_AutoID);
    TIntegerField *tblHI2AutoID = (TIntegerField *)ptblHI2->FieldByName(TTableHI::strfHI_AutoID);
    TStringField *tblHICompte = (TStringField *)ptblHI->FieldByName( TTableHI::strfHI_Compte);
    TStringField *tblHILibelleOperation = (TStringField *)ptblHI->FieldByName( TTableHI::strfHI_LibelleOperation);
    TBooleanField *tblHIEstCrediteur = (TBooleanField *)ptblHI->FieldByName( TTableHI::strfHI_EstCrediteur);
    TDateTimeField* pfldHI2DateDebPeriode = (TDateTimeField*)ptblHI2->FindField( TTableHI::strfHI_DateDebPeriode);
    TDateTimeField* pfldHI2DateFinPeriode = (TDateTimeField*)ptblHI2->FindField( TTableHI::strfHI_DateFinPeriode);
    #ifdef _DEBUG
    TIntegerField *tblHICodeDevise = (TIntegerField *)ptblHI->FieldByName(TTableHI::strfHI_CodeDevise);
    TCurrencyField* pfldHIMontant = (TCurrencyField *)ptblHI->FieldByName(TTableHI::strfHI_Montant);
    #endif

    for(bEntierementAnnulee = false;;)
    {
      ASSERT(ptblHI->Bof);

      do
      {
        ptblHI2->SetKey();
        tblHI2AutoID->AsInteger = tblHIAutoID->AsInteger;
        thlHI2Trouve = ptblHI2->GotoKey();
        uFlags = pfldHIFlags->AsInteger;
        bTesterPiece = false;

        ASSERT((uFlags & (TTableHI::HIFLAGS_EST_ANNULEE | TTableHI::HIFLAGS_ECART_ARRONDI)) != (TTableHI::HIFLAGS_EST_ANNULEE | TTableHI::HIFLAGS_ECART_ARRONDI)); // Un écart d'arrondi ne peut jamais être annulé

        if(!(uFlags & TTableHI::HIFLAGS_EST_ANNULEE) || bEntierementAnnulee)
        { // On est en cours de recopie de l'écriture entièrement annulée
          // ou bien cette ligne est modifiable par l'utilisateur...
          if ( uFlags & TTableHI::HIFLAGS_ECART_ARRONDI) {
            // Une ligne d'écart d'arrondi est toujours en monnaie du dossier et pour une écriture
            // dans une devise autre que celle du dossier.
            ASSERT((tblHICodeDevise->AsInteger == DeviseCodeDefaut) && (devEcriture.Code != DeviseCodeDefaut));
          } else if ( LIGNE_EST_ECART_CHANGE( uFlags)) {
            // Une ligne d'écart de change est toujours en monnaie du dossier et pour une écriture
            // dans une devise autre que celle du dossier.
            ASSERT((tblHICodeDevise->AsInteger == DeviseCodeDefaut) && (devEcriture.Code != DeviseCodeDefaut));
            ASSERT( pfldHIMontantO->AsCurrency == pfldHIMontant->AsCurrency);
            ASSERT( pEcartCh);

            CCompte    tmpCompte;
                       tmpCompte.Compte = tblHICompte->AsString;
            pEcartCh->Add( tmpCompte,
                           tblHILibelleOperation->AsString,
                           tblHIEstCrediteur->AsBoolean,
                           pfldHIMontantO->AsCurrency);
          } else {
            bTesterPiece = true;
            //... et ce n'est pas un écart d'arrondi ni un écart de change
            Append(); // Validation automatique (via Post()) des éventuelles modifications précédentes
            FieldValues[ strFldDst]    = ptblHI->FieldValues[ strFldSrc];
            if (thlHI2Trouve)
            {
              FieldValues[ strFldDst2] = ptblHI2->FieldValues[ strFldSrc2];
              if(pfldHI2DateDebPeriode && pfldHITmpDateDebPeriode)
              {
                if(pfldHI2DateDebPeriode->IsNull)
                     pfldHITmpDateDebPeriode->Clear();
                else pfldHITmpDateDebPeriode->AsDateTime = pfldHI2DateDebPeriode->AsDateTime;
              }
              if(pfldHI2DateFinPeriode && pfldHITmpDateFinPeriode)
              {
                if(pfldHI2DateFinPeriode->IsNull)
                     pfldHITmpDateFinPeriode->Clear();
                else pfldHITmpDateFinPeriode->AsDateTime = pfldHI2DateFinPeriode->AsDateTime;
              }
            }
            pfldHITmpEstNouvelleLigne->AsBoolean = false;

            ASSERT(pfldHITmpDebit->IsNull && pfldHITmpCredit->IsNull);
            ASSERT(!pfldHIEstCrediteur->IsNull);

            (pfldHIEstCrediteur->AsBoolean ? pfldHITmpCredit : pfldHITmpDebit)->AsCurrency = pfldHIMontantO->AsCurrency;
            pfldHITmpIDImageModifie->AsBoolean = pfldHIFlags->AsInteger & TTableHI::HIFLAGS_IMAGE_MODIFIEE;

            ASSERT(tblHICodeDevise->AsInteger == devEcriture.Code);
          }
        }

        if(!bEntierementAnnulee)
        { // Opérations lors de la tentative de copie de l'écriture non entièrement annulée
          if(bPieceConstante && bTesterPiece)
          { // => Vérification de l'unicité de la pièce (même sur les lignes annulées)
            if(pfldHIPiece->AsString != strPieceConstante)
            { // La pièce n'est plus constante
              bPieceConstante = false;
            }
          }

          if(pbarre)
          { // => Progression
            (*pbarre)++;
          }
        }

        ptblHI->Next();
      } while(!ptblHI->Eof);

      First(); // Positionnement (et validation automatique des dernières modifications apportées) au début de la copie
      if(!bEntierementAnnulee)
      { // On vient de tenter la copie d'une écriture à priori non entièrement annulée
        if(IsEmpty())
        { // On supposait que l'écriture n'était pas entièrement annulée mais ce n'est pas le cas
          // => On va copier l'écriture complète (qui est entièrement annulée) et
          //    que l'utilisateur ne pourra donc pas modifier
          ptblHI->First();
          bEntierementAnnulee = true;
          bModifiable         = false;
          continue;
        }
        else
        { // L'écriture n'est pas entièrement annulée et l'utilisateur peut la modifier
          // => Notification à l'appelant
          bModifiable = true;
        }
      }

      // La copie est terminée
      ASSERT(!IsEmpty());
      break;
    }

    ptblHI->PopFilter(fidEcriture);
    ptblHI->EnableControls();
  } catch(Exception& e) {
    ptblHI->PopFilter(fidEcriture);
    ptblHI->EnableControls();
    ptblHI2->MasterFields = strMasterFields;
    ptblHI2->MasterSource = ds;
    throw EUser(TAG(351), e);
  }

  bAnnulee    = bEntierementAnnulee;
  bPieceConst = bPieceConstante;
  if(bPieceConstante)
    strPieceConst = strPieceConstante;
  ptblHI2->MasterFields = strMasterFields;
  ptblHI2->MasterSource = ds;
  return(bModifiable);
 } /* TTableHITmp::CopyEcritureFrom() */


void __fastcall TTableHITmp::VerifierINV(const AnsiString &Journal,const TDateTime &DateImputation)
{
  if((( Journal=="INVS") || ( Journal=="INVC")) && ( DateImputation!=cm_DateSituation)) {
    EICAttention(EICFormat("La saisie d'une écriture sur les journaux 'INVS' et 'INVC' ne peut se faire qu'à la date de situation (%s).\n"
                           "\n"
                           "Veuillez modifier soit le journal, soit la date de l'écriture.",FormatDateTime("dd/mm/yyyy",cm_DateSituation).c_str()));
    Abort();
  }
}



 /******************************************************************************\
 ************* TTableHITmp::ValideEcriture() ************************************
 ********************************************************************************
 *                                                                              *
 *    Cette procédure permet de valider l'écriture contenue dans la table HI    *
 * temporaire (si la table est vide, la procédure ne fait rien) i.e. de créer   *
 * une nouvelle écriture ou de mettre à jour une écriture existante.            *
 *                                                                              *
 * Paramètres :                                                                 *
 *   nID            : ID de l'écriture à créer (IdEcritureNouvelle pour créer   *
 *                    une nouvelle écriture ou un ID d'écriture déjà existant   *
 *                    pour mettre à jour l'écriture en question).               *
 *   eIDRAO         : ID RAO de l'écriture (-1 si l'écriture n'est pas issue    *
 *                    d'un assistant, MAKELONG(cIDEcriture, szPREFIXE_MODULE)).*
 *   eHIFlagEcriture: Type de l'écriture (TTableHI::HIFLAGS_NORMALE(NORMALE|    *
 *                    A_CONTREPASSER)/IMPORTEE pour une normale(saisie en      *
 *                    fonction de base ou créée par un assistant)/importée.     *
 *   devEcriture    : Devise de l'écriture                                      *
 *   dateImputation : Date d'imputation de l'écriture                           *
 *   strCodeJnl     : Code du journal dans lequel l'écriture doit être passée   *
 *   bPieceConst    : TRUE si la pièce est constante sur l'écriture             *
 *   strPieceConst  : Pièce constante de l'écriture (ignorée si !bPieceConst)   *
 *   strNaturePiece : Nature de la pièce associée à l'écriture                  *
 *   ptblHIDst      : Historique qui doit recevoir l'écriture                   *
 *   ptblPCDst      : Plan comptable associé à l'historique                     *
 *   pbarre         : Barre de progression à utiliser (NULL = aucune)           *
 *   pnIDEcrValidee : Retourne le n° de l'écriture validée (NULL pour ignorer)  *
 \******************************************************************************/
 void __fastcall TTableHITmp::ValideEcriture( int                      nID,            // ID de l'écriture à passer  (= IdEcritureNouvelle si nouvelle ecriture )
                                              unsigned int             eIDRAO,         // Id de l'assistant ou du produit qui a généré l'écriture
                                              TTableHI::THIFlags       eHIFlagEcriture,// Type de l'écriture (normale ou importée)
                                              const CDevise&           devEcriture,    // Devise de l'écriture
                                              const TDateTime&         dtImputation, // Date de passage de l'écriture
                                              const AnsiString&        strCodeJournal,     // Journal ou est passée l'écriture
                                              bool                     bPieceConst,    // TRUE si la pièce de l'écriture est constante sur toutes ses lignes
                                              const AnsiString&        strPieceConstPrm,  // Pièce constante de l'écriture (ignorée si bPieceConstante == false)
                                              const AnsiString&        strNaturePiece, // Nature de la pièce de l'écriture
                                              const TEcartChgEcriture *pEcartCh,       // Liste des lignes d'écart de change calculée a intégrées dans l'écriture
                                              TTableHI*                ptblHIDst,      // HI auquel l'ecriture est integrée
                                              CTable*                  ptblHI2Dst,      // HI auquel l'ecriture est integrée
                                              TTablePC*                ptblPCDst,      // PC auquel l'ecriture est integrée
                                              const AnsiString &IDEcriturePart,        //Identifiant de l'écriture partenaire
                                              CBarre*                  pbarre,         // Barre de progression à utiliser
                                              int*                     pnIDEcrValidee) // Retourne le n° de l'écriture validée
 {
  AnsiString      strPieceConst( strPieceConstPrm);
  EICTag          tag;
  CPropsEcriture* ppe;         // Propriétés de l'écriture à valider
  bool            bEcartArr;   // TRUE s'il faut calculer/générer un écart d'arrondi sur l'écriture
  TCurrencyField* pfldDebit;   // Le champ "Débit"  de l'écriture à valider
  TCurrencyField* pfldCredit;  // "    "   "Crédit" "       "     "    "
  Currency        curSolde;    // Le solde de l'écriture à valider
  Currency        curEcartArr; // Valeur de l'écart d'arrondi de l'écriture (>0 = débiteur; < 0 = créditeur )
  int             nSaveIdEcriture = nID; // Sauvegarde de l'ID d'écriture à changer
   bool           bCalcPieceConst = false;
   AnsiString     strCalcPieceConst;
  TDateTime       dateImputation( dtImputation);
  AnsiString      strCodeJnl( strCodeJournal),AncienIndexName(ptblHIDst->IndexName);
  #ifdef _DEBUG
   int            nTmpIDLigne;      // L'ID d'écriture de la ligne courante
   int            nIDLignePrec = 0; // Pour vérifier la validité des ID d'une écriture à valider
   Currency       curSolde1a5;      // Solde des comptes 1 à 5 de l'écriture à valider
   Currency       curSolde6et7;     //   "    "     "    6 & 7 "       "     "    "

   ptblHIDst->IndexName = EmptyStr;

   TIntegerField* pfldHITmpIDLigne((TIntegerField*)FieldByName(strfHITmp_IDLigne));
   TStringField*  pfldHITmpCompte( (TStringField*) FieldByName(strfHITmp_Compte));
  #endif

   ptblHIDst->IndexName = EmptyStr;

  // Pour le journal INVC forçage du flag 'à contrepasser'
  #pragma option -w-eas
  if( strCodeJnl=="INVC")
      eHIFlagEcriture |= TTableHI::HIFLAGS_A_CONTREPASSER;
  #pragma option -w+eas

  // Pour les journaux INVS et INVC forçage de la date de l'écriture à la date de situation
  VerifierINV(strCodeJnl,dateImputation);
/*  if((( strCodeJnl=="INVS") || ( strCodeJnl=="INVC")) && ( dateImputation!=cm_DateSituation)) {
    EICAttention(EICFormat("La saisie d'une écriture sur les journaux 'INVS' et 'INVC' ne peut se faire qu'à la date de situation (%s).\n"
                           "\n"
                           "Veuillez modifier soit le journal, soit la date de l'écriture.",FormatDateTime("dd/mm/yyyy",cm_DateSituation).c_str()));
    Abort();
  }*/

  ASSERT(ptblHIDst);
  ASSERT(ptblPCDst);
  ASSERT((eHIFlagEcriture == TTableHI::HIFLAGS_NORMALE) ||
          (eHIFlagEcriture == (TTableHI::HIFLAGS_NORMALE | TTableHI::HIFLAGS_A_CONTREPASSER)) ||
          (eHIFlagEcriture == TTableHI::HIFLAGS_IMPORTEE));

  // Une écriture d'assistant est obligatoirement normale...
  //                          ...ou a contrepasser dans "INVR" obligatoirement
  ASSERT((eIDRAO == RAOIDECRITURE_FONCTION_BASE) ||
          IS_APRODUCTIDECRITURE(eIDRAO) ||
          (eHIFlagEcriture == TTableHI::HIFLAGS_NORMALE) ||
          ((eHIFlagEcriture == (TTableHI::HIFLAGS_NORMALE | TTableHI::HIFLAGS_A_CONTREPASSER)) &&
            (strCodeJnl == "INVR")));
  #ifdef _DEBUG
  //Une écriture du journal INVC est forcément à contrepasser
    if (strCodeJnl == "INVC")
      ASSERT(eHIFlagEcriture == (TTableHI::HIFLAGS_NORMALE | TTableHI::HIFLAGS_A_CONTREPASSER));
  //Les écritures des journaux INVR, INVC et INVS sont forcément à la date de cloture
    if ((strCodeJnl == "INVR") || (strCodeJnl == "INVC") || (strCodeJnl == "INVS"))
      ASSERT(cm_DateSituation == dateImputation);
  #endif
  // Une écriture importée est obligatoirement nouvelle (elle ne peut pas être modifiée)
  ASSERT((eHIFlagEcriture != TTableHI::HIFLAGS_IMPORTEE) ||
          (nID == IdEcritureNouvelle));
  // Le dossier doit être en FRF ou en EUR
  ASSERT((DeviseCodeDefaut == DeviseCodeFranc) || (DeviseCodeDefaut == DeviseCodeEuro));


  /////////////////////////////////////////////////////
  // Vérification de la validité légale de la devise //
  /////////////////////////////////////////////////////
  if( eHIFlagEcriture != TTableHI::HIFLAGS_IMPORTEE)
  { AnsiString strErrMsg;

    if(!DeviseEstValide(dateImputation, devEcriture, strErrMsg))
      throw EUser(TAG(360), EICFormat(MAKEINTRESOURCE(IDS_EXCEPTION_ECRITURE_INVALID_FmtMSGDEVISEINVALIDE), strErrMsg.c_str()));
  }

  ppe = NULL;
  if(pbarre)
    pbarre->Max = 2 * (DWORD)RecordCount;


  //////////////////////////////////////////////////////////////////////////////////
  // Vérification du solde de l'écriture à valider et calcul de l'écart de change //
  //////////////////////////////////////////////////////////////////////////////////
  tag = TAG(361);
  DisableControls();
  try {
    if( eHIFlagEcriture != TTableHI::HIFLAGS_IMPORTEE)
    {
      Currency curMontant;  // Un montant à valider (>0 = créditeur; < 0 = débiteur)

      ASSERT(curSolde == 0.);

      tag = TAG(362);
      pfldDebit  = (TCurrencyField*)FieldByName(strfHITmp_Debit);
      pfldCredit = (TCurrencyField*)FieldByName(strfHITmp_Credit);

      bEcartArr = (devEcriture.Code != DeviseCodeDefaut);

      First();
      while(!Eof)
      {
        #ifdef _DEBUG
         ASSERT(pfldCredit->IsNull ^ pfldDebit->IsNull);
         if((nTmpIDLigne = pfldHITmpIDLigne->AsInteger) != 0)
         { ASSERT(nTmpIDLigne > nIDLignePrec);
           nIDLignePrec = nTmpIDLigne;
         }
        #endif

        curSolde   +=
        curMontant  = (pfldCredit->IsNull) ? pfldDebit->AsCurrency : -pfldCredit->AsCurrency;
        if(bEcartArr)
          curEcartArr += DeviseConvToDef(devEcriture, curMontant);

        #ifdef _DEBUG
         switch(*pfldHITmpCompte->AsString.c_str())
         {
          case '1':
          case '2':
          case '3':
          case '4':
          case '5':
            curSolde1a5 += curMontant;
            break;
          case '6':
          case '7':
            curSolde6et7 -= curMontant;
            break;
         }
        #endif

        if( !bPieceConst) {
          if( Bof) {
            ASSERT( !bCalcPieceConst);
            bCalcPieceConst   = true;
            strCalcPieceConst = FieldByName( strfHITmp_Piece)->AsString;
          } else
            bCalcPieceConst  &= ( FieldByName( strfHITmp_Piece)->AsString==strCalcPieceConst);
        }

        Next();
        if(pbarre)
          (*pbarre)++;
      }

      if( !bPieceConst && bCalcPieceConst) {
        bPieceConst   = true;
        strPieceConst = strCalcPieceConst;
      }

      if(curSolde != (int)0)
        throw Exception(EICFormat(MAKEINTRESOURCE(IDS_EXCEPTION_ECRITURE_FmtDATE_FmtJNL_EST_FmtDESEQUILIBREE_FmtDEVISE),
                                         dateImputation.DateString().c_str(), strCodeJnl.c_str(),
                                         CurrToStr(curSolde).c_str(), devEcriture.CodeISO.c_str()
                                       ));
      #ifdef _DEBUG
        if(curSolde1a5 != curSolde6et7) { ASSERT(false); EICThrowInvalidArgument(TAG(364));}
      #endif
      ASSERT(bEcartArr || (curEcartArr == (int)0));
      if(bEcartArr && (curEcartArr == (int)0))
      { // L'écart de change calculé est nul
        // => Il n'y a pas d'écart à générer
        bEcartArr = false;
      }
    }
    else
    { // Ecriture importée => Pas d'écart d'arrondi car on importe toujours dans la devise du dossier
      bEcartArr = false;
    }

    // Si l'écriture est une nouvelle écriture, on vérifie que les champs
    // Lettrage, FlagLettrage, DateEP et EstNouvelleLigne sont bien initialisés
    // à cause de la duplication d'écriture
    tag = TAG( 466);
    if( nID==IdEcritureNouvelle) {
      SCAN_TABLE( this) {
        if( !FieldByName( TTableHITmp::strfHITmp_Lettrage        )->IsNull    ||
            !FieldByName( TTableHITmp::strfHITmp_DateEP          )->IsNull    ||
            !FieldByName( TTableHITmp::strfHITmp_EstNouvelleLigne)->AsBoolean ||
          ( !FieldByName( TTableHITmp::strfHITmp_IDLigne     )->AsInteger!=0) ||
          (  FieldByName( TTableHITmp::strfHITmp_FlagLettrage)->AsInteger!=TTableHI::HIFLAG_LETTRAGE_NON_LETTRE)) {
          Edit();
          FieldByName( TTableHITmp::strfHITmp_Lettrage        )->Clear();
          FieldByName( TTableHITmp::strfHITmp_DateEP          )->Clear();
          FieldByName( TTableHITmp::strfHITmp_EstNouvelleLigne)->AsBoolean = true;
          FieldByName( TTableHITmp::strfHITmp_IDLigne         )->AsInteger = 0;
          FieldByName( TTableHITmp::strfHITmp_FlagLettrage    )->AsInteger = TTableHI::HIFLAG_LETTRAGE_NON_LETTRE;
          Post();
        }
      }
    }
    ////////////////////////////////////////////////////////////////////////
    // Détermination des opérations de validation de la nouvelle écriture //
    ////////////////////////////////////////////////////////////////////////
    if(nID != IdEcritureNouvelle)
    { // La nouvelle écriture est une rectification d'une écriture déjà existante
      // => Les propriétés de l'écriture d'origine ont-elles été modifiées ?
      tag = TAG(365);
      if(!ptblHIDst->Locate(TTableHI::strfHI_IDEcriture, nID, _loNormal))
        EICThrowInvalidArgument(TAG(366));

      // Supprime tous les lettrages des lignes supprimées
      AnsiString strBookmark( ptblHIDst->Bookmark);
      TIntegerField *pfldHIDstIDEcriture = ( TIntegerField*)ptblHIDst->FieldByName( TTableHI::strfHI_IDEcriture);
      TIntegerField *pfldHIDstAutoID     = ( TIntegerField*)ptblHIDst->FieldByName( TTableHI::strfHI_AutoID    );
      TIntegerField *pfldHIDstFlags      = ( TIntegerField*)ptblHIDst->FieldByName( TTableHI::strfHI_Flags     );
      while(( pfldHIDstIDEcriture->AsInteger==nID) && !ptblHIDst->Eof) {
        if( !ptblHIDst->EstNonLettre && !Locate( strfHITmp_IDLigne, pfldHIDstAutoID->AsInteger, _loNormal))
             ptblHIDst->Delettrer( TTableHI::HIAD_DELETTRER_LA_LIGNE_ET_PRELETTRER_LE_RESTE);
        if( pEcartCh && LIGNE_EST_ECART_CHANGE( pfldHIDstFlags->AsInteger)) {
          for( int i=0; i<pEcartCh->Count; i++) {
            if(( pEcartCh->Items[i]->Compte.Compte==ptblHIDst->FieldByName( TTableHI::strfHI_Compte)->AsString) &&
               ( pEcartCh->Items[i]->bIsCrediteur==ptblHIDst->FieldByName( TTableHI::strfHI_EstCrediteur)->AsBoolean) &&
               ( pEcartCh->Items[i]->curMontant==ptblHIDst->FieldByName( TTableHI::strfHI_Montant)->AsCurrency) &&
               ( pEcartCh->Items[i]->nReference==0)) {
               pEcartCh->Items[i]->nReviseur  = ptblHIDst->FieldByName( TTableHI::strfHI_Reviseur )->AsInteger;
               pEcartCh->Items[i]->nReference = ptblHIDst->FieldByName( TTableHI::strfHI_Reference)->AsInteger;
               break;
            }
          }
        }
        ptblHIDst->Next();
      }
      ptblHIDst->Bookmark = strBookmark;


      tag = TAG(367);
      // L'écriture d'un AN ne peut pas être annulé puis recréée

        if((                 ptblHIDst->FieldValues[ TTableHI::strfHI_DateImputation]        != Variant(dateImputation)) ||
            (                 ptblHIDst->FieldByName(TTableHI::strfHI_CodeJournal)->AsString != strCodeJnl)               ||
            (bPieceConst && (ptblHIDst->FieldByName(TTableHI::strfHI_Piece)->AsString != strPieceConst))           ||
            (                 ptblHI2Dst->FieldByName(TTableHI::strfHI_NaturePiece)->AsString != strNaturePiece)           ||
            (        CDevise(ptblHIDst->FieldByName(TTableHI::strfHI_CodeDevise)->AsInteger,
                               ptblHIDst->FieldByName(TTableHI::strfHI_TauxChange)->AsFloat)  != devEcriture)
          )
        { // Une des propriétés de l'écriture à rectifier a été modifiée
          // => On annule l'écriture d'origine et...
          int nIdNew;
          tag = TAG(368);
          ptblHIDst->m_bDelLettrage = CDevise( ptblHIDst->FieldByName(TTableHI::strfHI_CodeDevise)->AsInteger,
                                               ptblHIDst->FieldByName(TTableHI::strfHI_TauxChange)->AsFloat) != devEcriture;
          if( ptblHIDst->m_bDelLettrage) {
            for( First(); !Eof; Next()) { Edit(); FieldByName( strfHITmp_Lettrage)->Clear(); Next(); }
          }
          ptblHIDst->AnnulerEcritureSansTest(nID, ptblPCDst,ptblHI2Dst, &nIdNew, false);
          ptblHIDst->m_bDelLettrage = false;

          // ...on va créer une nouvelle écriture
          nSaveIdEcriture = IdEcritureNouvelle;
          nID = IdEcritureNouvelle;
        }
    }

    ///////////////////////////////////////////////
    // Rectification (ou création) de l'écriture //
    ///////////////////////////////////////////////
    // => Création des propriétés de la nouvelle écriture
    //    (une écriture avec un nouvel ID sera obligatoirement générée qu'il faille créer une
    //    écriture totalement nouvelle ou bien qu'il faille rectifier une écriture existante)
    tag = TAG(369);
    ppe = new CPropsEcriture(ptblHIDst->CreerIDNouvelleEcriture(),
                              eHIFlagEcriture, devEcriture,
                              strCodeJnl, dateImputation,
                              bPieceConst, strPieceConst, strNaturePiece,
                              eIDRAO,IDEcriturePart);

    // => Rectification/Création de l'écriture
    tag = TAG(370);
    ptblHIDst->RectifierEcriture(nID, *ppe, this, ptblPCDst, ptblHI2Dst,pbarre);

    // => Ajout de l'écart d'arrondi à l'écriture
    if(bEcartArr)
    {
      tag = TAG(371);
      ptblHIDst->AjouterEcartArrondi(*ppe, ptblPCDst,ptblHI2Dst, curEcartArr);
    }

    // => Ajout de l'écart de change si la liste n'est pas nulle
    if ( pEcartCh) {
      ASSERT( pEcartCh->Count>0);
      ptblHIDst->AjouterEcartsChange( *ppe, ptblPCDst,ptblHI2Dst, pEcartCh);
    }

    if ( nSaveIdEcriture!=IdEcritureNouvelle) {
      ptblHIDst->ChangeIDEcriture( ppe->IDEcriture, nSaveIdEcriture);
      if(pnIDEcrValidee)
        *pnIDEcrValidee = nSaveIdEcriture;
    } else {
      if(pnIDEcrValidee)
        *pnIDEcrValidee = ppe->IDEcriture;
    }
    // => Destruction des propriétés de l'écriture
    delete ppe;
  } catch(Exception& e) {
    // Annulation du mode transactionnel
    ptblHIDst->Cancel();
    ptblHI2Dst->Cancel();
    ptblPCDst->Cancel();
    delete ppe;
    EnableControls();
    throw EUser(tag, e);
  }
  ptblHIDst->IndexName = AncienIndexName;

  ////////////////////////////////////////////
  // Validation immédiate des modifications //
  ////////////////////////////////////////////
  if( eHIFlagEcriture != TTableHI::HIFLAGS_IMPORTEE)
  { // Cette validation n'est pas faite pour les écritures importées pour accélérer l'import
    try {
      ptblHIDst->FlushBuffers();
      ptblPCDst->FlushBuffers();
    } catch(...) {
    }
  }

  EnableControls();
 } /* TTableHITmp::ValideEcriture() */



 /******************************************************************************\
 ************* TTablePT::GetEstVise() *******************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction renvoi TRUE si le programme de travail courant est visé    *
 *                                                                              *
 \******************************************************************************/
 bool __fastcall TTablePT::GetEstVise()
 {
  return(FieldByName(strfPT_Visa)->AsBoolean);
 } /* TTablePT::GetEstVise() */


 /******************************************************************************\
 ************* TTablePT::EstToutVise() ******************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction renvoi TRUE si tous les programmes de travail sont visés.  *
 *                                                                              *
 * Paramètres :                                                                 *
 *   Racine   : Racine du programme de travail                                  *
 *                                                                              *
 \******************************************************************************/
bool __fastcall TTablePT::EstToutVise(const AnsiString &Racine,bool *RacineVide)
{
  try
    {
      AnsiString AncienFilter(Filter);
      bool AncienFiltered(Filtered);
      FiltrerRacine(Racine);
      if (IsEmpty())
        {//Toutes les consignes sont visées quand il n'y a aucune consigne
          Filter = AncienFilter;
          Filtered = AncienFiltered;
          if (RacineVide)
            *RacineVide = true;                  //La racine est vide
          return true;
        }
      if (RacineVide)
        *RacineVide = false;                     //La racine n'est pas vide
      First();
      while (!Eof)
        {
          if (!GetEstVise())
            {//Au moins une consigne de pas visée
              Filter = AncienFilter;
              Filtered = AncienFiltered;
              return false;
            }
          Next();
        }//Toutes les consignes sont visées
      Filter = AncienFilter;
      Filtered = AncienFiltered;
      return true;
    }
  catch(Exception& e)
    {
      throw EUser(TAG(380),e);
    }
} /* TTablePT::EstToutVise() */


 /******************************************************************************\
 ************* TTablePT::GetMemo() **********************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de renvoyer le texte de la consigne courante        *
 *                                                                              *
 \******************************************************************************/
AnsiString __fastcall TTablePT::GetMemo()
{
  ASSERT(!IsEmpty());

  return FieldByName(szfPT_Consigne)->AsString;
} /* TTablePT::GetMemo() */


 /******************************************************************************\
 ************* TTablePT::SetMemo() **********************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de changer le texte d'une consigne                  *
 *                                                                              *
 * Paramètres :                                                                 *
 *   Texte   : Texte de la consigne                                             *
 *                                                                              *
 \******************************************************************************/
void __fastcall TTablePT::SetMemo(AnsiString & Texte)
{
  ASSERT(!IsEmpty());

  try
    {
      Edit();
      FieldByName(szfPT_Consigne)->AsString = Texte;
      Post();
    }
  catch(Exception& e)
    {
      Cancel();
      throw EUser(TAG(390),e);
    }
} /* TTablePT::SetMemo() */


 /******************************************************************************\
 ************* TTablePT::ViserConsigne() ****************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de viser la consigne courante et de modifier en     *
 *    conséquence le visa du programme de travail si la table est donnée.       *
 *                                                                              *
 * Paramètres :                                                                 *
 *   bViser   : TRUE s'il faut viser                                            *
 *   Table_PC   : table PC                                                      *
 *                                                                              *
 \******************************************************************************/
void __fastcall TTablePT::ViserConsigne(bool bViser)
{
  ASSERT(!IsEmpty());

  try
    {
      Edit();
      FieldByName(strfPT_Visa)->AsBoolean = bViser;        //On pose le visa sur le PT
      Post();
    }
  catch(Exception& e)
    {
      Cancel();
      throw EUser(TAG(400),e);
    }
} /* TTablePT::ViserConsigne() */


 /******************************************************************************\
 ************* TTablePT::CreerConsigne() ****************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de créer une consigne                               *
 *                                                                              *
 * Paramètres :                                                                 *
 *   Racine   : Racine du programme de travail                                  *
 *   Consigne : Texte de la consigne                                            *
 *   TypeCondition : consigne dossier ou commune                                *
 *                                                                              *
 \******************************************************************************/
bool __fastcall TTablePT::CreerConsigne(const AnsiString &Racine,
                                        const AnsiString &Consigne,
                                         PTTypeCondition TypeCondition)
{
  AnsiString AncienFilter(Filter);
  bool AncienFiltered(Filtered);
  int Ordre;
  TFilterRecordEvent AncienOnFilterRecord = OnFilterRecord;
  try
    {
      FiltrerRacine(Racine);
      Ordre = OrdreSuivant(TypeCondition);
      Append();
      FieldByName(strfPT_Visa)->AsBoolean = false;
      FieldByName(strfPT_Racine)->AsString = Racine;
      FieldByName(strfPT_Ordre)->AsInteger = Ordre;
      FieldByName(strfPT_TypeCondition)->AsInteger = (int)TypeCondition;
      FieldByName(strfPT_Consigne)->AsString = Consigne;
      Post();
    }
  catch(Exception& e)
    {
      Cancel();
      Filter = AncienFilter;
      Filtered = AncienFiltered;
      return false;
    }
  Filter = AncienFilter;
  Filtered = AncienFiltered;
  OnFilterRecord = AncienOnFilterRecord;
  Locate(strfPT_Ordre,Ordre,_loNormal);
  return true;
} /* TTablePT::CreerConsigne() */


 /******************************************************************************\
 ************* TTablePT::OrdreSuivant() *****************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de le numéro d'ordre de la prochaine consignes.     *
 *    On recherche le premier numéro libre à partir du minimum (1,1000 ou 2000).*
 *                                                                              *
 * Paramètres :                                                                 *
 *   Dossier : TRUE si l'on veut l'ordre suivant d'une consigne niveau dossier. *
 *                                                                              *
 \******************************************************************************/
int __fastcall TTablePT::OrdreSuivant(PTTypeCondition TypeCond)
{
  #define MIN_COMMUN_INCONDITIONNEL 1
  #define MIN_COMMUN_CONDITIONNEL 1000
  #define MIN_DOSSIER 2000

  try
    {
      if (IsEmpty())
        switch (TypeCond)
          {
            case PTTYPECONDITION_CONDITIONNEL_COMMUN:
              return MIN_COMMUN_CONDITIONNEL;
            case PTTYPECONDITION_INCONDITIONNEL_COMMUN:
              return MIN_COMMUN_INCONDITIONNEL;
            default:
              ASSERT(TypeCond == PTTYPECONDITION_DOSSIER);
              return MIN_DOSSIER;
          }
      switch (TypeCond)
        {
          case PTTYPECONDITION_INCONDITIONNEL_COMMUN:
            {
              int Ordre(MIN_COMMUN_INCONDITIONNEL);
              First();
              while (!Eof &&
                     (FieldByName(strfPT_Ordre)->AsInteger <= Ordre))
                {
                  if (FieldByName(strfPT_Ordre)->AsInteger >= MIN_COMMUN_INCONDITIONNEL)
                    Ordre++;
                  Next();
                }
              return Ordre;
            }
          case PTTYPECONDITION_CONDITIONNEL_COMMUN:
            {
              int Ordre(MIN_COMMUN_CONDITIONNEL);
              First();
              while (!Eof &&
                     (FieldByName(strfPT_Ordre)->AsInteger <= Ordre))
                {
                  if (FieldByName(strfPT_Ordre)->AsInteger >= MIN_COMMUN_CONDITIONNEL)
                    Ordre++;
                  Next();
                }
              return Ordre;
            }
          default :
            ASSERT(TypeCond == PTTYPECONDITION_DOSSIER);
            {
              int Ordre(MIN_DOSSIER);
              First();
              while (!Eof &&
                     (FieldByName(strfPT_Ordre)->AsInteger <= Ordre))
                {
                  if (FieldByName(strfPT_Ordre)->AsInteger >= MIN_DOSSIER)
                    Ordre++;
                  Next();
                }
              return Ordre;
            }
        }
    }
  catch(Exception& e)
    {
      throw EUser(TAG(410),e);
    }
} /* TTablePT::OrdreSuivant() */


 /******************************************************************************\
 ************* TTablePT::FiltrerRacine() ****************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de filtrer un programme de travail                  *
 *                                                                              *
 * Paramètres :                                                                 *
 *   Racine   : Racine                                                          *
 * ATTENTION : Ne jamais utiliser avec FiltrerVisaCondition                     *
 *                                                                              *
 \******************************************************************************/
void __fastcall TTablePT::FiltrerRacine(const AnsiString&Racine)
{
  Filter = szfPT_Racine "='" + Racine + "'";
  Filtered = true;
}


 /******************************************************************************\
 ************* TTablePT::fmFiltrerComptesMouvementes() **************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de filtrer les consignes conditionnelles.           *
 *                                                                              *
 \******************************************************************************/
void __fastcall TTablePT::fmFiltrerComptesMouvementes(TDataSet *DataSet, bool &Accept)
{
  Accept = (FieldByName(strfPT_TypeCondition)->AsInteger != PTTYPECONDITION_CONDITIONNEL_COMMUN);
} /* TTablePT::fmFiltrerComptesMouvementes() */


 /******************************************************************************\
 ************* TTablePT::FiltrerComptesMouvementes() ****************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de filtrer un programme de travail                  *
 *                                                                              *
 * Paramètres :                                                                 *
 *   bVisa : TRUE si l'on veut montrer les consignes visées                     *
 *   bPresenceCompteMouvemente : si TRUE on affiche pas les consignes condition-*
 *     nelles à la présence de comptes.                                         *
 * ATTENTION : Ne jamais utiliser avec FiltrerRacine                            *
 *                                                                              *
 \******************************************************************************/
void __fastcall TTablePT::FiltrerComptesMouvementes(TTablePC * Table_PC)
{
  if (ComptesMouvementes(Table_PC))
    OnFilterRecord = 0;
  else
    OnFilterRecord = fmFiltrerComptesMouvementes;
} /* TTablePT::FiltrerComptesMouvementes() */


 /******************************************************************************\
 ************* TTablePT::ViserRacine() ******************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de viser un programme de travail et de viser les    *
 *    consignes correspondantes.                                                *
 *                                                                              *
 * Paramètres :                                                                 *
 *   Racine : N° du programme de travail                                        *
 *   bViser : TRUE s'il faut viser                                              *
 *   Table_PT   : table PT                                                      *
 *                                                                              *
 \******************************************************************************/
void __fastcall TTablePT::ViserRacine(const AnsiString &Racine,bool bViser)
{
  bool AncienFiltered;
  TIntegerField *tblPTTypeCondition;
  AnsiString AncienFilter;
  AncienFilter = Filter;
  AncienFiltered = Filtered;
  try
    {
      DisableControls();
      Close();  //On ferme la table pour appliquer le filtre
      FiltrerRacine(Racine);
      Open();
      tblPTTypeCondition = (TIntegerField *)FieldByName(strfPT_TypeCondition);
      while (!Eof)                               //Viser chaque consigne
        {
          switch (tblPTTypeCondition->AsInteger)
            {
              case PTTYPECONDITION_ANCIEN_COMMUN:
                break;  //On ne (dé)vise pas les anciens PT, pour retrouver leurs valeurs plus tard
              default:
                ViserConsigne(bViser);
            }
          Next();
        }
      Filter = AncienFilter;
      Filtered = AncienFiltered;
      EnableControls();
    }
  catch(Exception& e)
    {
      Filter = AncienFilter;
      Filtered = AncienFiltered;
      EnableControls();
      throw EUser(TAG(420),e);
    }
} /* TTablePT::ViserRacine() */


 /******************************************************************************\
 ************* TTablePT::SupprimerConsignes() ***********************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de supprimer du programme de travail toutes les     *
 *    consignes d'une racine.                                                   *
 *                                                                              *
 * Paramètres :                                                                 *
 *   Racine   : Racine                                                          *
 *                                                                              *
 \******************************************************************************/
void __fastcall TTablePT::SupprimerConsignes(AnsiString & Racine)
{
  AnsiString AncienFilter(Filter);
  bool AncienFiltered(Filtered);
  try
    {
      FiltrerRacine(Racine);
      while (!IsEmpty())
        SupprimerConsigne();
      Filter = AncienFilter;
      Filtered = AncienFiltered;
    }
  catch(Exception& e)
    {
      Filter = AncienFilter;
      Filtered = AncienFiltered;
      throw EUser(TAG(440),e);
    }
} /* TTablePT::SupprimerConsignes() */


 /******************************************************************************\
 ************* TTablePT::SupprimerConsigne() ************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de supprimer une consigne du programme de travail.  *
 *                                                                              *
 \******************************************************************************/
void __fastcall TTablePT::SupprimerConsigne()
{
  ASSERT(!IsEmpty());

  try
    {
      Delete();
    }
  catch(Exception& e)
    {
      throw EUser(TAG(450),e);
    }
} /* TTablePT::SupprimerConsigne() */


 /******************************************************************************\
 ************* TTablePT::MonterConsigne() ***************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de monter une consigne du programme de travail.     *
 *    True est renvoyé si la consigne est montée.                               *
 *                                                                              *
 \******************************************************************************/
bool __fastcall TTablePT::MonterConsigne()
{
  ASSERT(!IsEmpty());

  try
    {
      Prior();
      if (Bof)
        return false;                            //On n'est pas sur la première consigne
      int OrdreHaut(FieldByName(strfPT_Ordre)->AsInteger);
      DescendreConsigne();
      Locate(strfPT_Ordre,OrdreHaut,_loNormal);
    }
  catch(Exception& e)
    {
      throw EUser(TAG(460),e);
    }
  return true;
} /* TTablePT::MonterConsigne() */


 /******************************************************************************\
 ************* TTablePT::DescendreConsigne() ************************************
 ********************************************************************************
 *                                                                              *
 *    Cette fonction permet de monter une consigne du programme de travail.     *
 *    True est renvoyé si la consigne est descendue.                            *
 *                                                                              *
 \******************************************************************************/
bool __fastcall TTablePT::DescendreConsigne()
{
  #define ORDRE_TMP 0
  ASSERT(!IsEmpty());

  int OrdreHaut(FieldByName(strfPT_Ordre)->AsInteger);
  int OrdreBas;
  Next();
  if (Eof)
    return false;                                //On est sur la dernière consigne
  OrdreBas = FieldByName(strfPT_Ordre)->AsInteger;
  try
    {
      Edit();
      FieldByName(strfPT_Ordre)->AsInteger = ORDRE_TMP;
      Post();
      Locate(strfPT_Ordre,OrdreHaut,_loNormal);
      Edit();
      FieldByName(strfPT_Ordre)->AsInteger = OrdreBas;
      Post();
      Locate(strfPT_Ordre,ORDRE_TMP,_loNormal);
      Edit();
      FieldByName(strfPT_Ordre)->AsInteger = OrdreHaut;
      Post();
      Locate(strfPT_Ordre,OrdreBas,_loNormal);
    }
  catch(Exception& e)
    {
      Cancel();
      throw EUser(TAG(470),e);
    }
  return true;
} /* TTablePT::DescendreConsigne() */


 /******************************************************************************\
 ************* TTablePT::ComptesMouvementes() ***********************************
 ********************************************************************************
 *                                                                              *
 *  Cette fonction revoie TRUE s'il existe au moins un compte mouvementés pour  *
 *  la racine courante.                                                         *
 *                                                                              *
 \******************************************************************************/
bool __fastcall TTablePT::ComptesMouvementes(TTablePC * Table_PC)
{
  ASSERT(Table_PC);
  ASSERT(!Table_PC->IsEmpty());

  AnsiString AncienFilter(Table_PC->Filter);
  bool AncienFiltered(Table_PC->Filtered);
  AnsiString AncienCompte(Table_PC->FieldByName(TTablePC::strfPC_Compte)->AsString);
  bool AuMoinsUnCompteMouvemente(false);
  if (IsEmpty())
    return true;                                 //Il n'y a pas de consignes donc pas de consignes conditionnelles (la valeur de retour n'a pas d'importance)
  try
    {
      Table_PC->Filter = AnsiString("Compte='") + Table_PC->FieldByName(TTablePC::strfPC_Compte)->AsString + "*'";
      Table_PC->Filtered = true;
      Table_PC->First();
      while (!(Table_PC->Eof || AuMoinsUnCompteMouvemente))
        {//On est pas en fin de table et on a pas encore trouvé un compte mouvementé
           AuMoinsUnCompteMouvemente = Table_PC->EstMouvemente;
           Table_PC->Next();
        }
      Table_PC->Filter = AncienFilter;
      Table_PC->Filtered = AncienFiltered;
      Table_PC->AllerSurLeProgrammeDeTravail(AncienCompte);
      
      ASSERT(Table_PC->FieldByName(szfPC_TypeEnr)->AsInteger == TTablePC::PCTYPEENR_PROGRAMME_DE_TRAVAIL);
    }
  catch(Exception& e)
    {
      Table_PC->Filter = AncienFilter;
      Table_PC->Filtered = AncienFiltered;
      Table_PC->AllerSurLeProgrammeDeTravail(AncienCompte);
      throw EUser(TAG(480),e);
    }
  return AuMoinsUnCompteMouvemente;
 } /* TTablePT::ComptesMouvementes() */




 /******************************************************************************\
 ************* TTablePC::SupprimerAncienPTCommun() ******************************
 ********************************************************************************
 *                                                                              *
 *                                                                              *
 \******************************************************************************/
bool __fastcall TTablePC::SupprimerAncienPTCommun(TTablePT * Table_PT,CBarre *Barre /*= 0*/)
{
  #if (PCTYPEENR_PROGRAMME_DE_TRAVAIL != 1)
    #error Revoir le code suivant
  #endif
  return Table_PT->SupprimerAncienPTCommun(Barre);         //On supprime les consignes du PT
} /* TTablePC::SupprimerAncienPTCommun() */




 /******************************************************************************\
 ************* TTablePC::RestaurerAncienVisaPTCommun() **************************
 ********************************************************************************
 *                                                                              *
 *                                                                              *
 \******************************************************************************/
bool __fastcall TTablePC::RestaurerAncienVisaPTCommun(TTablePT * Table_PT,CBarre *Barre /*= 0*/)
{
  #if (PCTYPEENR_PROGRAMME_DE_TRAVAIL != 1)
    #error Revoir le code suivant
  #endif
  FilterID IDFilter(FID_NUL);
  TIntegerField *Visa((TIntegerField *)FieldByName(strfPC_Visa));
  TStringField *Compte((TStringField *)FieldByName(strfPC_Compte));
  Table_PT->RestaurerAncienVisaPTCommun(Barre);
  try
    {
      PushFilter(IDFilter,szfPC_TypeEnr "=1");   //On ne garde que les PT
      Barre->Max = RecordCount;
      (*Barre) = 0;
      First();
      while (!Eof)
        {
          bool RacineVide;
          if (Table_PT->EstToutVise(Compte->AsString,&RacineVide))
            {//Toutes les consignes sont visées
              if (!RacineVide)
                {//La racine est vide, pas besoin de la viser
                  Edit();
                  Visa->AsInteger = PCVISA_PROGRAMME_DE_TRAVAIL;     //On vise le PT
                }
            }
          if (RacineVide)
            Delete();                            //Il n'y a pas de consigne, on supprime la racine
          else
            {
              Next();                            //Il y a des consignes
              (*Barre)++;
            }
        }
      PopFilter(IDFilter);
    }
  catch(Exception &e)
    {
      PopFilter(IDFilter);
      throw EUser(TAG(490),e);
    }
  return true;
} /* TTablePC::RestaurerAncienVisaPTCommun() */




 /******************************************************************************\
 ************* TTablePT::SupprimerAncienPTCommun() ******************************
 ********************************************************************************
 *                                                                              *
 *                                                                              *
 \******************************************************************************/
bool __fastcall TTablePT::SupprimerAncienPTCommun(CBarre *Barre /*= 0*/)
{
  #if (PTTYPECONDITION_INCONDITIONNEL_COMMUN != 0)
    #error Revoir le code suivant
  #endif
  #if (PTTYPECONDITION_CONDITIONNEL_COMMUN != 1)
    #error Revoir le code suivant
  #endif
  FilterID IDFilter(FID_NUL);
  TIntegerField *TypeCondition((TIntegerField *)FieldByName(strfPT_TypeCondition));
  TDataSource *AncienMasterSource(MasterSource);
  MasterSource = 0;
  try
    {
      PushFilter(IDFilter,szfPT_TypeCondition "=1");       //On filtre que les PT conditionnels
      Barre->Max = RecordCount;
      (*Barre) = 0;
      First();
      while (!Eof)                               //On supprime tous les conditionnels
        {
          Delete();
          (*Barre)++;
        }
      PopFilter(IDFilter);
      PushFilter(IDFilter,szfPT_TypeCondition "=0");       //On filtre que les PT inconditionnels
      Barre->Max = RecordCount;
      (*Barre) = 0;
      First();
      while (!Eof)
        {
          Edit();                                //On passe toutes les consignes en anciennes consignes
          TypeCondition->AsInteger = PTTYPECONDITION_ANCIEN_COMMUN;
          First();
          (*Barre)++;
        }
      PopFilter(IDFilter);
      MasterSource = AncienMasterSource;
    }
  catch(Exception &e)
    {
      PopFilter(IDFilter);
      MasterSource = AncienMasterSource;
      throw EUser(TAG(500),e);
    }
  return true;
} /* TTablePT::SupprimerAncienPTCommun() */




 /******************************************************************************\
 ************* TTablePT::RestaurerAncienVisaPTCommun() **************************
 ********************************************************************************
 *                                                                              *
 *                                                                              *
 \******************************************************************************/
bool __fastcall TTablePT::RestaurerAncienVisaPTCommun(CBarre *Barre /*= 0*/)
{
  #if ((PTTYPECONDITION_ANCIEN_COMMUN != 3) || (PTTYPECONDITION_INCONDITIONNEL_COMMUN != 0))
    #error Revoir le code suivant
  #endif
  FilterID IDFilterAncien(FID_NUL),IDFilterNouveau(FID_NUL);
  TBooleanField *pVisa((TBooleanField *)FieldByName(strfPT_Visa));
  TStringField *pCompte((TStringField *)FieldByName(strfPT_Racine));
  TStringField *pTexte((TStringField *)FieldByName(strfPT_Consigne));
  AnsiString Compte,Texte;
  TDataSource *AncienMasterSource(MasterSource);
  MasterSource = 0;
  try
    {
      PushFilter(IDFilterAncien,szfPT_TypeCondition "=3"); //On ne garde que les anciennes consignes
      Barre->Max = RecordCount;
      (*Barre) = 0;
      while (!IsEmpty())
        {
          First();                               //On est sur la première ancienne consigne
          if (pVisa->AsBoolean)
            {//L'ancienne consigne était visée => on recolle le visa
              Compte = pCompte->AsString;
              Texte = pTexte->AsString;
              try
                {
                  PushFilter(IDFilterNouveau,AnsiString(szfPT_TypeCondition "=0 AND " szfPT_Racine "='") + Compte + "'");        //On garde les nouvelles consignes de même compte que l'ancienne courante
                  First();
                  while (!Eof)
                    {
                      if (Texte == pTexte->AsString)
                        {//On a retrouvé (exactement) la même consigne (même racine, même consigne)
                          Edit();
                          pVisa->AsBoolean = true;         //On recolle le visa
                          Post();
                          break;                 //On arrête la recherche
                        }
                      Next();
                    }
                  PopFilter(IDFilterNouveau);
                }
              catch(Exception &e)
                {
                  PopFilter(IDFilterNouveau);
                  throw EUser(TAG(510),e);
                }
              First();                           //On revient sur la première ancienne consigne
            }
          Delete();                              //On detruit sur la première ancienne consigne
          (*Barre)++;
        }
      PopFilter(IDFilterAncien);
      MasterSource = AncienMasterSource;
    }
  catch(Exception &e)
    {
      PopFilter(IDFilterAncien);
      MasterSource = AncienMasterSource;
      throw EUser(TAG(511),e);
    }
  return true;
} /* TTablePT::RestaurerAncienVisaPTCommun() */

//*******************//
// TEcartChgEcriture //
//***************************************************************************
//
//   Classe servant à la gestion d'une liste d'écart de change à générer
// dans une écriture. Chaque élément correspond a une ligne de l'écriture.
//
//***************************************************************************
__fastcall TEcartChgEcriture::TEcartChgEcriture()
{
  m_pLstEcr = new TList();
}
//---------------------------------------------------------------------------
__fastcall TEcartChgEcriture::~TEcartChgEcriture()
{
  Clear();
  delete m_pLstEcr;
}
//---------------------------------------------------------------------------
int __fastcall TEcartChgEcriture::GetCount() const
{
  return m_pLstEcr->Count;
}
//---------------------------------------------------------------------------
void __fastcall TEcartChgEcriture::Add( const CCompte &vCompte, const AnsiString &vstrLibelle, bool vbIsCrediteur, const Currency &vcurMontant)
{
  TLigneEcartChange sChange;

  sChange.Compte       = vCompte;
  sChange.strLibelle   = vstrLibelle;
  sChange.bIsCrediteur = vbIsCrediteur;
  sChange.curMontant   = vcurMontant;
  sChange.nReviseur    = 0;
  sChange.nReference   = 0;

  Add( sChange);
}
//---------------------------------------------------------------------------
void __fastcall TEcartChgEcriture::Add( const TLigneEcartChange &sChange)
{
  TLigneEcartChange *psChange = NULL;

  try {
     psChange = new TLigneEcartChange();
    *psChange = sChange;
     m_pLstEcr->Add( (void*)psChange);
  } catch ( Exception &e) {
    throw EUser( TAG(599), e);
  }
}
//---------------------------------------------------------------------------
TLigneEcartChange *__fastcall TEcartChgEcriture::GetItems( int nIndex) const
{
  return ( TLigneEcartChange *)m_pLstEcr->Items[ nIndex];
}
//---------------------------------------------------------------------------
void __fastcall TEcartChgEcriture::Delete( int nIndex)
{
  delete Items[ nIndex];
  m_pLstEcr->Delete( nIndex);
}
//---------------------------------------------------------------------------
void __fastcall TEcartChgEcriture::Clear()
{
  while ( m_pLstEcr->Count) Delete( 0);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
__fastcall CLignesEcriture::CLignesEcriture()
{
  m_pEcr = new TList;
}
//---------------------------------------------------------------------------
__fastcall CLignesEcriture::~CLignesEcriture()
{
  Clear();
  delete m_pEcr;
}
//---------------------------------------------------------------------------
int __fastcall CLignesEcriture::GetCount() const
{
  return m_pEcr->Count;
}
//---------------------------------------------------------------------------
int __fastcall CLignesEcriture::Add( const AnsiString &strCompte, const AnsiString &strLibelleOp, bool bEstCrediteur, const Currency &curMontantOrigine, const AnsiString &strPiece /* = EmptyStr */, const AnsiString &strNaturePiece /* = EmptyStr */, const AnsiString &strPieceExt /* = EmptyStr */)
{
  return m_pEcr->Add( new CLigneEcriture( strCompte, strLibelleOp, bEstCrediteur, curMontantOrigine, strPiece, strNaturePiece, strPieceExt));
}
//---------------------------------------------------------------------------
int __fastcall CLignesEcriture::Add( const AnsiString &strCompte, const AnsiString &strLibelleOp, bool bEstCrediteur, const Currency &curMontantOrigine, TCodeDev eCodeDevise, double dTaux, const AnsiString &strPiece /* = EmptyStr */, const AnsiString &strNaturePiece /* = EmptyStr */, const AnsiString &strPieceExt /* = EmptyStr */)
{
  return m_pEcr->Add( new CLigneEcriture( strCompte, strLibelleOp, bEstCrediteur, curMontantOrigine, eCodeDevise, dTaux, strPiece, strNaturePiece, strPieceExt));
}
//---------------------------------------------------------------------------
CLigneEcriture *CLignesEcriture::GetLigneEcriture( int nIndex) const
{
  ASSERT( nIndex<Count);
  return ( CLigneEcriture *)m_pEcr->Items[nIndex];
}
//---------------------------------------------------------------------------
void __fastcall CLignesEcriture::Clear()
{
  for( int i=0; i<Count; i++) delete Ligne[i];
  m_pEcr->Clear();
}
//---------------------------------------------------------------------------
void __fastcall CLignesEcriture::Delete( int nIndex)
{
  ASSERT( nIndex<Count);
  delete Ligne[nIndex];
  m_pEcr->Delete( nIndex);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
__fastcall CLigneEcriture::CLigneEcriture( const AnsiString &strCompte,
                                           const AnsiString &strLibelleOp,
                                                  bool       bEstCrediteur,
                                           const Currency   &curMontantOrigine,
                                           const AnsiString &strPiece /* = EmptyStr */,
                                           const AnsiString &strNaturePiece /* = EmptyStr */,
                                           const AnsiString &strPieceExt /* = EmptyStr */)
{
  Init( strCompte, strLibelleOp, bEstCrediteur, curMontantOrigine, 0, 0, strPiece, strNaturePiece, strPieceExt);
}
//---------------------------------------------------------------------------
__fastcall CLigneEcriture::CLigneEcriture( const AnsiString &strCompte,
                                           const AnsiString &strLibelleOp,
                                                 bool        bEstCrediteur,
                                           const Currency   &curMontantOrigine,
                                                 TCodeDev    eCodeDevise,
                                                 double      dTaux,
                                           const AnsiString &strPiece /* = EmptyStr */,
                                           const AnsiString &strNaturePiece /* = EmptyStr */,
                                           const AnsiString &strPieceExt /* = EmptyStr */)
{
  Init( strCompte, strLibelleOp, bEstCrediteur, curMontantOrigine, eCodeDevise, dTaux, strPiece, strNaturePiece, strPieceExt);
}
//---------------------------------------------------------------------------
void __fastcall CLigneEcriture::Init( const AnsiString &strCompte, const AnsiString &strLibelleOp, bool bEstCrediteur, const Currency &curMontantOrigine, TCodeDev eCodeDevise, double dTaux, const AnsiString &strPiece, const AnsiString &strNaturePiece, const AnsiString &strPieceExt)
{
  m_strCompte            = strCompte;
  m_dateRANOrigine       = TDateTime( 0);
  m_strRANJournalOrigine = EmptyStr;
  m_strPiece             = strPiece;
  m_strLettrage          = EmptyStr;
  m_nFlagLettrage        = TTableHI::HIFLAG_LETTRAGE_NON_LETTRE;
  m_strLibelleOperation  = strLibelleOp;
  m_curMontantOrgine     = curMontantOrigine;
  m_codeDevise           = eCodeDevise;
  m_dTaux                = dTaux;
  m_bEstCrediteur        = bEstCrediteur;
  m_nFlags               = TTableHI::HIFLAGS_EST_NORMALE;
  m_strIDEcriturePart    = EmptyStr;
  m_strRAOData           = EmptyStr;
  m_dtDateDebPeriode     = TDateTime( 0);
  m_dtDateFinPeriode     = TDateTime( 0);
  m_nIDImage             = -1;
  m_strDesignation       = EmptyStr;
  m_dtDateEcheance       = TDateTime( 0);
  m_dQuantite            = D_NS;
  m_strBanquePaiement    = EmptyStr;
  m_eModePaiement        = MP_AUCUN;
  m_dTauxTVA             = D_NS;
  m_strCodeTVA           = EmptyStr;
  m_strNaturePiece       = strNaturePiece;
  m_strPieceExt          = strPieceExt;
  m_dtRapprochement      = 0;
  m_nReviseur            = 0;
  m_nReference           = 0;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
__fastcall CEcriture::CEcriture( const TDateTime    &dateImputation,
                                 const AnsiString   &strCodeJnl,
                                       MODE_PAIEMENT eNaturePiece /* = MP_AUCUN */,
                                       int           nRAOIDLigne  /* = -1 */)
{
  ASSERT( dateImputation!=TDateTime( 0));
  ASSERT( !strCodeJnl.IsEmpty());

  Init( dateImputation, strCodeJnl, 0, 0, nRAOIDLigne, eNaturePiece, false);
}
//---------------------------------------------------------------------------
__fastcall CEcriture::CEcriture(       TCodeDev      eCodeDevise,
                                       double        dTaux,
                                 const TDateTime    &dateImputation,
                                 const AnsiString   &strCodeJnl,
                                       MODE_PAIEMENT eNaturePiece /* = MP_AUCUN */,
                                       int           nRAOIDLigne  /* = -1 */)
{
  ASSERT( dateImputation!=TDateTime( 0));
  ASSERT( !strCodeJnl.IsEmpty());

  Init( dateImputation, strCodeJnl, eCodeDevise, dTaux, nRAOIDLigne, eNaturePiece, true);
}
//---------------------------------------------------------------------------
__fastcall CEcriture::~CEcriture()
{
  delete m_pLignesEcr;
  delete m_pEcartsChange;
}
//---------------------------------------------------------------------------
void __fastcall CEcriture::Init( const TDateTime    &dateImputation,
                                 const AnsiString   &strCodeJnl,
                                       TCodeDev      eCodeDevise,
                                       double        dTaux,
                                       int           nRAOIDLigne,
                                       MODE_PAIEMENT eNaturePiece,
                                       bool          bDeviseConst/*,const AnsiString &strIDEcriturePart*/)
{
  m_dateImputation   = dateImputation;
  m_strCodeJournal   = strCodeJnl;
  m_codeDevise       = eCodeDevise;
  m_dTaux            = dTaux;
  m_nRAOIDLigne      = nRAOIDLigne;
  m_bDeviseConstante = bDeviseConst;
  m_eNaturePiece     = eNaturePiece;
  m_nIDEcriture      = IdEcritureNouvelle;
  m_pLignesEcr       = new CLignesEcriture;
  m_pEcartsChange    = new CLignesEcriture;
}
//---------------------------------------------------------------------------
__fastcall CEcriture::CEcriture( CTable *ptbl,CTable *ptbl2, int nIdEcr)
{
  TStringField *ptblCodeJournal,*ptbl2RAOIDLigne,*ptblCompte,*ptblLibelleOperation,*ptblPiece,*ptbl2NaturePiece,*ptbl2PieceExterne,*ptbl2RANJnlOrigine,*ptblLettrage,*ptbl2IDEcriturePart,*ptbl2RAOData,*ptbl2Designation,*ptbl2Banque,*ptbl2CodeTVA,*ptbl2CodeAnalytik;
  TBooleanField *ptblEstCrediteur;
  TCurrencyField *ptblMontantOrigine;
  TIntegerField *ptblCodeDevise,*ptblFlags,*ptblIDEcriture,*ptblFlagLettrage,*ptblIDImage,*ptblModePaiement,*ptblReviseur,*ptblReference;
  TFloatField *ptblTauxChange,*ptbl2Quantite,*ptbl2TauxTVA;
  TDateTimeField *ptblDateImputation,*ptbl2RANDateOrigine,*ptblDateEcheance,*ptblDateEP,*ptbl2DateDebPeriode,*ptbl2DateFinPeriode;

  ASSERT( ptbl->Active);
  ASSERT(!ptbl->Filtered);

  ptblCodeJournal = (TStringField *)ptbl->FieldByName(TTableHI::strfHI_CodeJournal);
  ptbl2RAOIDLigne = (TStringField *)ptbl2->FieldByName(TTableHI::strfHI_RAOIDLigne);
  ptblCompte = (TStringField *)ptbl->FieldByName(TTableHI::strfHI_Compte);
  ptblLibelleOperation = (TStringField *)ptbl->FieldByName(TTableHI::strfHI_LibelleOperation);
  ptblEstCrediteur = (TBooleanField *)ptbl->FieldByName(TTableHI::strfHI_EstCrediteur);
  ptblMontantOrigine = (TCurrencyField *)ptbl->FieldByName(TTableHI::strfHI_MontantOrigine);
  ptblCodeDevise = (TIntegerField *)ptbl->FieldByName(TTableHI::strfHI_CodeDevise);
  ptblFlags = (TIntegerField *)ptbl->FieldByName(TTableHI::strfHI_Flags);
  ptblIDEcriture = (TIntegerField *)ptbl->FieldByName(TTableHI::strfHI_IDEcriture);
  ptblTauxChange = (TFloatField *)ptbl->FieldByName(TTableHI::strfHI_TauxChange);
  ptblPiece = (TStringField *)ptbl->FieldByName(TTableHI::strfHI_Piece);
  ptbl2NaturePiece = (TStringField *)ptbl2->FieldByName(TTableHI::strfHI_NaturePiece);
  ptbl2PieceExterne = (TStringField *)ptbl2->FieldByName(TTableHI::strfHI_PieceExterne);
  ptblDateImputation = (TDateTimeField *)ptbl->FieldByName(TTableHI::strfHI_DateImputation);
  ptbl2RANDateOrigine = (TDateTimeField *)ptbl2->FieldByName(TTableHI::strfHI_RANDateOrigine);
  ptbl2RANJnlOrigine = (TStringField *)ptbl2->FieldByName(TTableHI::strfHI_RANJnlOrigine);
  ptblLettrage = (TStringField *)ptbl->FieldByName(TTableHI::strfHI_Lettrage);
  ptblFlagLettrage = (TIntegerField *)ptbl->FieldByName(TTableHI::strfHI_FlagLettrage);
  ptbl2IDEcriturePart = (TStringField *)ptbl2->FieldByName(TTableHI::strfHI_IDEcriturePart);
  ptbl2RAOData = (TStringField *)ptbl2->FieldByName(TTableHI::strfHI_RAOData);
  ptbl2DateDebPeriode = (TDateTimeField *)ptbl2->FindField(TTableHI::strfHI_DateDebPeriode);
  ptbl2DateFinPeriode = (TDateTimeField *)ptbl2->FindField(TTableHI::strfHI_DateFinPeriode);
  ptblIDImage = (TIntegerField *)ptbl->FieldByName(TTableHI::strfHI_IDImage);
  ptbl2Designation = (TStringField *)ptbl2->FieldByName(TTableHI::strfHI_Designation);
  ptblDateEcheance = (TDateTimeField *)ptbl->FieldByName(TTableHI::strfHI_DateEcheance);
  ptbl2Quantite = (TFloatField *)ptbl2->FieldByName(TTableHI::strfHI_Quantite);
  ptbl2Banque = (TStringField *)ptbl2->FieldByName(TTableHI::strfHI_Banque);
  ptblModePaiement = (TIntegerField *)ptbl->FieldByName(TTableHI::strfHI_ModePaiement);
  ptbl2TauxTVA = (TFloatField *)ptbl2->FieldByName(TTableHI::strfHI_TauxTVA);
  ptbl2CodeTVA = (TStringField *)ptbl2->FieldByName(TTableHI::strfHI_CodeTVA);
  ptblDateEP = (TDateTimeField *)ptbl->FieldByName(TTableHI::strfHI_DateEP);
  ptblReviseur = (TIntegerField *)ptbl->FieldByName(TTableHI::strfHI_Reviseur);
  ptblReference = (TIntegerField *)ptbl->FieldByName(TTableHI::strfHI_Reference);
  ptbl2CodeAnalytik = (TStringField *)ptbl2->FieldByName(TTableHI::strfHI_CodeAnalytik);

  TBookmark bmHI = ptbl->GetBookmark();
  // Recherche le début de l'écriture
  if ( !ptbl->Locate( TTableHI::strfHI_IDEcriture, nIdEcr, TLocateOptions() << loCaseInsensitive)) return;
  // Lit les valeurs communes
  AnsiString    strBookmark    = ptbl->Bookmark;
  TDateTime     dateImputation = ptblDateImputation->AsDateTime;
  AnsiString    strCodeJournal = ptblCodeJournal->AsString;
  TCodeDev      eCodeDevise    = ptblCodeDevise->AsInteger;
  double        dTaux          = ptblTauxChange->AsFloat;
  int           nRAOIDLigne    = ptbl2RAOIDLigne->AsInteger;
  AnsiString    strNaturePiece = ptbl2NaturePiece->AsString;
  MODE_PAIEMENT eNaturePiece   = ::ComptaGetModePaiement( strNaturePiece);
  bool          bDeviseConst   = true;
  bool          bNatPieceConst = true;
  // Vérifie que la devise est constante sur toute l'écriture
  while(( ptblIDEcriture->AsInteger==nIdEcr) && !ptbl->Eof) {
    if ( !LIGNE_EST_ECART_ARRONDI( ptblFlags->AsInteger) &&
         !LIGNE_EST_ECART_CHANGE ( ptblFlags->AsInteger)) {
      bDeviseConst   &= (( ptblCodeDevise->AsInteger==eCodeDevise) &&
                         ( ptblTauxChange->AsFloat  ==dTaux      ));
      bNatPieceConst &=  ( ptbl2NaturePiece->AsString==strNaturePiece);
    }
    ptbl->Next();
  }
  // Initialise la structure
  if( !bNatPieceConst) eNaturePiece = MP_AUCUN;
  if(  bDeviseConst) Init( dateImputation, strCodeJournal, eCodeDevise, dTaux, nRAOIDLigne, eNaturePiece, true );
                else Init( dateImputation, strCodeJournal,           0,     0, nRAOIDLigne, eNaturePiece, false);
  m_nIDEcriture = nIdEcr;
  // Insére toutes les lignes de l'écriture
  ptbl->Bookmark = strBookmark;
  while(( ptblIDEcriture->AsInteger==nIdEcr) && !ptbl->Eof) {
    int             nIndex;
    CLigneEcriture *pLigne;

    if ( LIGNE_EST_ECART_ARRONDI( ptblFlags->AsInteger)) {
      // Ajout d'une ligne d'écart d'arrondi
      // ...
      // ...
    } else if ( LIGNE_EST_ECART_CHANGE( ptblFlags->AsInteger)) {
      // Ajout d'une ligne d'écart de change
      ASSERT(( ptblCodeDevise->AsInteger==DeviseCodeEuro ) ||
             ( ptblCodeDevise->AsInteger==DeviseCodeFranc));
      nIndex = EcartsChange->Add( ptblCompte->AsString,
                                  ptblLibelleOperation->AsString,
                                  ptblEstCrediteur->AsBoolean,
                                  ptblMontantOrigine->AsCurrency,
                                  ptblCodeDevise->AsInteger,
                                  ptblTauxChange->AsFloat,
                                  ptblPiece->AsString,
                                  ptbl2NaturePiece->AsString,
                                  ptbl2PieceExterne->AsString);
      // Ajout des champs peu utilisé
      pLigne                    = EcartsChange->Ligne[nIndex];
      pLigne->RANDateOrigine    = ptbl2RANDateOrigine->AsDateTime;
      pLigne->RANJournalOrigine = ptbl2RANJnlOrigine->AsString;
      pLigne->Lettrage          = ptblLettrage->AsString;
      pLigne->FlagLettrage      = ( TTableHI::HIFlagLettrage)ptblFlagLettrage->AsInteger;
      pLigne->Flags             = ptblFlags->AsInteger;
      pLigne->IDEcriturePart    = ptbl2IDEcriturePart->AsString;
      pLigne->RAOData           = ptbl2RAOData->AsString;
      if(ptbl2DateDebPeriode)
        pLigne->DateDebPeriode  = ptbl2DateDebPeriode->AsDateTime;
      if(ptbl2DateFinPeriode)
        pLigne->DateFinPeriode  = ptbl2DateFinPeriode->AsDateTime;
      pLigne->IDImage           = ptblIDImage->AsInteger;
      pLigne->Designation       = ptbl2Designation->AsString;
      pLigne->DateEcheance      = ptblDateEcheance->AsDateTime;
      pLigne->Quantite          = ptbl2Quantite->IsNull ? D_NS : ptbl2Quantite->AsFloat;
      pLigne->BanquePaiement    = ptbl2Banque->AsString;
      pLigne->ModePaiement      = ( MODE_PAIEMENT)( ptblModePaiement->IsNull ? MP_AUCUN : ptblModePaiement->AsInteger);
      pLigne->TauxTVA           = ptbl2TauxTVA->IsNull ? D_NS : ptbl2TauxTVA->AsFloat;
      pLigne->CodeTVA           = ptbl2CodeTVA->AsString;
      pLigne->DateRapprochement = ptblDateEP->AsDateTime;
      pLigne->Reviseur          = ptblReviseur->AsInteger;
      pLigne->Reference         = ptblReference->AsInteger;
    } else {
      // Ajout d'une ligne normale
      // Ajout des champs obligatoires et les plus courant
      if ( bDeviseConst) nIndex = LignesEcriture->Add( ptblCompte->AsString,
                                                       ptblLibelleOperation->AsString,
                                                       ptblEstCrediteur->AsBoolean,
                                                       ptblMontantOrigine->AsCurrency,
                                                       ptblPiece->AsString,
                                                       ptbl2NaturePiece->AsString,
                                                       ptbl2PieceExterne->AsString);
                    else nIndex = LignesEcriture->Add( ptblCompte->AsString,
                                                       ptblLibelleOperation->AsString,
                                                       ptblEstCrediteur->AsBoolean,
                                                       ptblMontantOrigine->AsCurrency,
                                                       ptblCodeDevise->AsInteger,
                                                       ptblTauxChange->AsFloat,
                                                       ptblPiece->AsString,
                                                       ptbl2NaturePiece->AsString,
                                                       ptbl2PieceExterne->AsString);
      // Ajout des champs peu utilisé
      pLigne                    = LignesEcriture->Ligne[nIndex];
      pLigne->RANDateOrigine    = ptbl2RANDateOrigine->AsDateTime;
      pLigne->RANJournalOrigine = ptbl2RANJnlOrigine->AsString;
      pLigne->Lettrage          = ptblLettrage->AsString;
      pLigne->FlagLettrage      = ( TTableHI::HIFlagLettrage)ptblFlagLettrage->AsInteger;
      pLigne->Flags             = ptblFlags->AsInteger;
      pLigne->IDEcriturePart    = ptbl2IDEcriturePart->AsString;
      pLigne->RAOData           = ptbl2RAOData->AsString;
      if(ptbl2DateDebPeriode)
        pLigne->DateDebPeriode  = ptbl2DateDebPeriode->AsDateTime;
      if(ptbl2DateFinPeriode)
        pLigne->DateFinPeriode  = ptbl2DateFinPeriode->AsDateTime;
      pLigne->IDImage           = ptblIDImage->AsInteger;
      pLigne->Designation       = ptbl2Designation->AsString;
      pLigne->DateEcheance      = ptblDateEcheance->AsDateTime;
      pLigne->Quantite          = ptbl2Quantite->IsNull ? D_NS : ptbl2Quantite->AsFloat;
      pLigne->BanquePaiement    = ptbl2Banque->AsString;
      pLigne->ModePaiement      = ( MODE_PAIEMENT)( ptblModePaiement->IsNull ? MP_AUCUN : ptblModePaiement->AsInteger);
      pLigne->TauxTVA           = ptbl2TauxTVA->IsNull ? D_NS : ptbl2TauxTVA->AsFloat;
      pLigne->CodeTVA           = ptbl2CodeTVA->AsString;
      pLigne->CodeAnalytique    = ptbl2CodeAnalytik->AsString;
      pLigne->DateRapprochement = ptblDateEP->AsDateTime;
      pLigne->Reviseur          = ptblReviseur->AsInteger;
      pLigne->Reference         = ptblReference->AsInteger;
    }

    ptbl->Next();
  }
  // Restaure la position du curseur
  ptbl->GotoBookmark( bmHI);
  ptbl->FreeBookmark( bmHI);
}
//---------------------------------------------------------------------------
void __fastcall CEcriture::AjouterLigneHI(       TTableHI           *ptblHI,
                                         const AnsiString         &strCompte,
                                         const AnsiString         &strPiece,
                                         const AnsiString         &strLettrage,
                                         TTableHI::HIFlagLettrage  eFlagLettrage,
                                         const AnsiString         &strLibelleOp,
                                         const Currency           &curMontantOrigine,
                                               TCodeDev            eCodeDevise,
                                               double              dTauxChange,
                                               bool                bEstCrediteur,
                                               int                 nFlags,
                                               int                 nIDImage,
                                         const TDateTime          &dtDateEcheance,
                                               MODE_PAIEMENT       eModePaiement,
                                         const TDateTime          &dtRappr,
                                               int                 nCodeReviseur,
                                               int                 nRef)
{
  ASSERT(( ptblHI->State==dsEdit) || ( ptblHI->State==dsInsert));

  ptblHI->FieldByName( TTableHI::strfHI_DateImputation  )->AsDateTime = DateImputation;
  ptblHI->FieldByName( TTableHI::strfHI_Compte          )->AsString   = strCompte;
  ptblHI->FieldByName( TTableHI::strfHI_CodeJournal     )->AsString   = CodeJournal;
  ptblHI->FieldByName( TTableHI::strfHI_Piece           )->AsString   = strPiece;
  ptblHI->FieldByName( TTableHI::strfHI_Lettrage        )->AsString   = strLettrage;
  ptblHI->FieldByName( TTableHI::strfHI_FlagLettrage    )->AsString   = eFlagLettrage;
  ptblHI->FieldByName( TTableHI::strfHI_IDEcriture      )->AsInteger  = IDEcriture;
  ptblHI->FieldByName( TTableHI::strfHI_LibelleOperation)->AsString   = strLibelleOp;
  ptblHI->FieldByName( TTableHI::strfHI_MontantOrigine  )->AsCurrency = curMontantOrigine;
  ptblHI->FieldByName( TTableHI::strfHI_CodeDevise      )->AsInteger  = eCodeDevise;
  if ( dTauxChange!=0) ptblHI->FieldByName( TTableHI::strfHI_TauxChange)->AsFloat = dTauxChange;
                  else ptblHI->FieldByName( TTableHI::strfHI_TauxChange)->Clear();
  ptblHI->FieldByName( TTableHI::strfHI_Montant         )->AsCurrency = DeviseConvToDef( CDevise( eCodeDevise, dTauxChange), curMontantOrigine);
  ptblHI->FieldByName( TTableHI::strfHI_EstCrediteur    )->AsBoolean  = bEstCrediteur;
  ptblHI->FieldByName( TTableHI::strfHI_Flags           )->AsInteger  = nFlags;
  if ( nIDImage>0) ptblHI->FieldByName( TTableHI::strfHI_IDImage)->AsInteger = nIDImage;
  if(( int)dtDateEcheance!=0) ptblHI->FieldByName( TTableHI::strfHI_DateEcheance)->AsDateTime = dtDateEcheance;
                         else ptblHI->FieldByName( TTableHI::strfHI_DateEcheance)->Clear();
  ptblHI->FieldByName( TTableHI::strfHI_ModePaiement)->AsInteger = eModePaiement;
  if(( int)dtRappr!=0) ptblHI->FieldByName( TTableHI::strfHI_DateEP)->AsDateTime = dtRappr;
                  else ptblHI->FieldByName( TTableHI::strfHI_DateEP)->Clear();
  ptblHI->FieldByName( TTableHI::strfHI_Reviseur        )->AsInteger  = nCodeReviseur;
  ptblHI->FieldByName( TTableHI::strfHI_Reference       )->AsInteger  = nRef;
}
//---------------------------------------------------------------------------
void __fastcall CEcriture::AjouterLigneHI2(        CTable           *ptblHI2,
                                         const TDateTime          &dateRANOrigine,
                                         const AnsiString         &strRANJnlOrigine,
                                         const AnsiString         &strIDEcriturePart,
                                         const AnsiString         &strRAOData,
                                         const AnsiString         &strDesignation,
                                               double              dQuantite,
                                         const AnsiString         &strBanquePaiement,
                                               double              dTauxTVA,
                                         const AnsiString         &strCodeTVA,
                                         const AnsiString         &strNaturePiece,
                                         const AnsiString         &strPieceExt,
                                         const AnsiString         &strCodeAnalytik,
                                         const TDateTime          &dateDebPeriode,
                                         const TDateTime          &dateFinPeriode)
{
  TDateTimeField *fDatePeriode = NULL;

  ASSERT(( ptblHI2->State==dsEdit) || ( ptblHI2->State==dsInsert));

  if (( int)dateRANOrigine!=0) ptblHI2->FieldByName( TTableHI::strfHI_RANDateOrigine)->AsDateTime = dateRANOrigine;
                          else ptblHI2->FieldByName( TTableHI::strfHI_RANDateOrigine)->Clear();
  ptblHI2->FieldByName( TTableHI::strfHI_RANJnlOrigine   )->AsString   = strRANJnlOrigine;
  ptblHI2->FieldByName( TTableHI::strfHI_PieceExterne    )->AsString   = strPieceExt;
  ptblHI2->FieldByName( TTableHI::strfHI_NaturePiece     )->AsString   = NaturePiece!=MP_AUCUN ? ::ComptaGetModePaiementAbreviation( NaturePiece) : strNaturePiece;
  ptblHI2->FieldByName( TTableHI::strfHI_RAOIDLigne      )->AsInteger  = RAOIDLigne;
  ptblHI2->FieldByName( TTableHI::strfHI_IDEcriturePart  )->AsString   = strIDEcriturePart;
  ptblHI2->FieldByName( TTableHI::strfHI_RAOData         )->AsString   = strRAOData;
  fDatePeriode = (TDateTimeField*)ptblHI2->FindField( TTableHI::strfHI_DateDebPeriode);
  if ( fDatePeriode) {
    if (( int)dateDebPeriode!=0) fDatePeriode->AsDateTime = dateDebPeriode;
                            else fDatePeriode->Clear();
  }
  fDatePeriode = (TDateTimeField*)ptblHI2->FindField( TTableHI::strfHI_DateFinPeriode);
  if ( fDatePeriode) {
    if (( int)dateFinPeriode!=0) fDatePeriode->AsDateTime = dateFinPeriode;
                            else fDatePeriode->Clear();
  }
  ptblHI2->FieldByName( TTableHI::strfHI_Designation     )->AsString   = strDesignation;
  if( dQuantite!=D_NS) ptblHI2->FieldByName( TTableHI::strfHI_Quantite)->AsFloat = dQuantite;
                  else ptblHI2->FieldByName( TTableHI::strfHI_Quantite)->Clear();
  ptblHI2->FieldByName( TTableHI::strfHI_Banque          )->AsString   = strBanquePaiement;
  if( dTauxTVA!=D_NS) ptblHI2->FieldByName( TTableHI::strfHI_TauxTVA)->AsFloat = dTauxTVA;
                 else ptblHI2->FieldByName( TTableHI::strfHI_TauxTVA)->Clear();
  ptblHI2->FieldByName( TTableHI::strfHI_CodeTVA         )->AsString   = strCodeTVA;
  ptblHI2->FieldByName( TTableHI::strfHI_CodeAnalytik    )->AsString   = strCodeAnalytik;
}
//---------------------------------------------------------------------------
void __fastcall CEcriture::ValideEcriture( TTableHI *ptblHI, TTablePC *ptblPC,CTable *ptblHI2, bool bMove, CBarre *pBarre /* = NULL */)
{
  int        nAContrePasser = 0;
  bool       bPieceConst    = true;
  AnsiString strPieceConst;
  // Vérifie que le solde de l'écriture en monnaie d'origine est nul
  Currency curSolde;

  if( m_bDeviseConstante) {
    for( int i=0; i<LignesEcriture->Count; i++) {
      CLigneEcriture *pLigne = LignesEcriture->Ligne[i];
      if ( pLigne->EstCrediteur) curSolde -= pLigne->MontantOrigine;
                            else curSolde += pLigne->MontantOrigine;
    }
    if ( curSolde!=0) ::EICThrowInvalidArgument( TAG( 500));
  }

  // Vérifier que l'on ne va pas modifier une écriture importée ( car non géré par la classe)
  if (( IDEcriture!=IdEcritureNouvelle) && EstEcritureImportee && !bMove) ::EICThrowInvalidArgument( TAG( 502));

  // Si on est en modification d'écriture, on commence par annuler l'ancienne
  // sinon on recréé un nouvel ID d'écriture
  if ( IDEcriture!=IdEcritureNouvelle) ptblHI->AnnulerEcritureSansTest( IDEcriture, ptblPC,ptblHI2, NULL, true);
                                  else m_nIDEcriture = ptblHI->CreerIDNouvelleEcriture();

  // On écrit une à une les lignes dans l'historique
  curSolde = 0;
  if ( pBarre) pBarre->Max = LignesEcriture->Count + EcartsChange->Count;
  for( int i=0; i<LignesEcriture->Count; i++) {
    CLigneEcriture *pLigne = LignesEcriture->Ligne[i];

    // Vérifie que le compte existe, sinon celui-ci est créé avec un intitulé vide
    if ( !ptblPC->AllerSurLeCompte( pLigne->Compte))
      ptblPC->CreerCompte( CCompte( pLigne->Compte.c_str(), NULL));

    if( pLigne->Flags & TTableHI::HIFLAGS_A_CONTREPASSER) nAContrePasser++;
    if( i==0) strPieceConst =   pLigne->Piece;
         else bPieceConst  &= ( pLigne->Piece==strPieceConst);

    ptblHI->Append();
    AjouterLigneHI( ptblHI,
                  pLigne->Compte,
                  pLigne->Piece,
                  bMove ? pLigne->Lettrage : EmptyStr,
                  bMove ? pLigne->FlagLettrage : TTableHI::HIFLAG_LETTRAGE_NON_LETTRE,
                  pLigne->LibelleOperation,
                  pLigne->MontantOrigine,
                  m_bDeviseConstante ? CodeDevise : pLigne->CodeDevise,
                  m_bDeviseConstante ? Taux : pLigne->Taux,
                  pLigne->EstCrediteur,
                  pLigne->Flags,
                  pLigne->IDImage,
                  pLigne->DateEcheance,
                  pLigne->ModePaiement,
                  pLigne->DateRapprochement,
                  pLigne->Reviseur,
                  pLigne->Reference);

    if ( pLigne->EstCrediteur) curSolde -= ptblHI->FieldByName( TTableHI::strfHI_Montant)->AsCurrency;
                          else curSolde += ptblHI->FieldByName( TTableHI::strfHI_Montant)->AsCurrency;

    // Change le solde du plan comptable
    ptblPC->ChangeSolde( pLigne->Compte, ptblHI->FieldByName( TTableHI::strfHI_Montant)->AsCurrency,
                         pLigne->EstCrediteur, DateImputation);

    ptblHI->Post();
    ptblHI2->Append();
    AjouterLigneHI2( ptblHI2,
                  pLigne->RANDateOrigine,
                  pLigne->RANJournalOrigine,
                  pLigne->IDEcriturePart,
                  pLigne->RAOData,
                  pLigne->Designation,
                  pLigne->Quantite,
                  pLigne->BanquePaiement,
                  pLigne->TauxTVA,
                  pLigne->CodeTVA,
                  pLigne->NaturePiece,
                  pLigne->PieceExterne,
                  pLigne->CodeAnalytique,
                  pLigne->DateDebPeriode,
                  pLigne->DateFinPeriode);
    ptblHI2->FieldByName(TTableHI::strfHI_AutoID)->AsInteger = ptblHI->FieldByName(TTableHI::strfHI_AutoID)->AsInteger;
    ptblHI2->Post();
    if ( pBarre) (*pBarre)++;
  }

#ifdef _DEBUG
  if( nAContrePasser)
    ASSERT( nAContrePasser==LignesEcriture->Count);
#endif

  // Si le solde en monnaie de tenue n'est pas nul, on passe un écart de conversion
  if ( curSolde!=0) {
    ptblPC->CreerComptesArrondis(); // Création éventuel des comptes d'arrondis
    bool       bCredit   = ( curSolde>0);
    AnsiString strCompte( bCredit ? TTablePC::cm_strCptProfiArrondis : TTablePC::cm_strCptPerteArrondis);
    ptblHI->Append();
    AjouterLigneHI( ptblHI,
                    strCompte,
                    bPieceConst ? strPieceConst : EmptyStr,
                    EmptyStr,
                    TTableHI::HIFLAG_LETTRAGE_NON_LETTRE,
                    EICFormat("Ecart d'arrondi %s -> %s",
                    CDevise( m_bDeviseConstante ? CodeDevise : DeviseCodeFranc, Taux).CodeISO.c_str(), DeviseDefaut->CodeISO.c_str()),
                    bCredit ? curSolde : -curSolde,
                    DeviseCodeDefaut,
                    DeviseCodeDefaut==DeviseCodeEuro ? 1 : 0,
                    bCredit,
                    TTableHI::HIFLAGS_EST_NORMALE | TTableHI::HIFLAGS_ECART_ARRONDI | ( nAContrePasser ? TTableHI::HIFLAGS_A_CONTREPASSER : 0),
                     -1,
                      0,
                    MP_AUCUN,
                    0, TTableHI::m_nReviseur, TTableHI::GetReferenceSuivante());
    // Change le solde du plan comptable
    ptblPC->ChangeSolde( strCompte, ptblHI->FieldByName( TTableHI::strfHI_Montant)->AsCurrency,
                         bCredit, DateImputation);
    ptblHI->Post();
    ptblHI2->Append();
    AjouterLigneHI2(ptblHI2,
                    0,
                    EmptyStr,
                    EmptyStr,//IDEcriturePart
                    EmptyStr,//RAOData
                    EmptyStr,//Designation
                    D_NS,    //Quantité
                    EmptyStr,//Banque
                    D_NS,    //Taux TVA
                    EmptyStr,//Code TVA
                    EmptyStr,//Nature pièce
                    EmptyStr,//Pièce externe
                    EmptyStr,
                    0,
                    0);
    ptblHI2->FieldByName(TTableHI::strfHI_AutoID)->AsInteger = ptblHI->FieldByName(TTableHI::strfHI_AutoID)->AsInteger;
    ptblHI2->Post();
  }

  // Si l'écriture contient des lignes d'écart de change, on les ajoute à la fin
  if ( EcartsChange->Count) {
    for( int i=0; i<EcartsChange->Count; i++) {
      CLigneEcriture *pEcartChange = EcartsChange->Ligne[i];
      ptblHI->Append();
      AjouterLigneHI( ptblHI,
                      pEcartChange->Compte,
                      bPieceConst ? strPieceConst : EmptyStr,
                      bMove ? pEcartChange->Lettrage : EmptyStr,
                      bMove ? pEcartChange->FlagLettrage : TTableHI::HIFLAG_LETTRAGE_NON_LETTRE,
                      pEcartChange->LibelleOperation,
                      pEcartChange->MontantOrigine,
                      DeviseCodeDefaut,
                      DeviseCodeDefaut==DeviseCodeEuro ? 1 : 0,
                      pEcartChange->EstCrediteur,
                      TTableHI::HIFLAGS_EST_NORMALE | TTableHI::HIFLAGS_ECART_CHANGE | ( nAContrePasser ? TTableHI::HIFLAGS_A_CONTREPASSER : 0),
                      pEcartChange->IDImage,
                      pEcartChange->DateEcheance,
                      pEcartChange->ModePaiement,
                      pEcartChange->DateRapprochement,
                      pEcartChange->Reviseur,
                      pEcartChange->Reference);
      ptblHI->Post();
      ptblHI2->Append();
      AjouterLigneHI2(ptblHI2,
                      pEcartChange->RANDateOrigine,
                      pEcartChange->RANJournalOrigine,
                      pEcartChange->IDEcriturePart,
                      pEcartChange->RAOData,
                      pEcartChange->Designation,
                      pEcartChange->Quantite,
                      pEcartChange->BanquePaiement,
                      pEcartChange->TauxTVA,
                      pEcartChange->CodeTVA,
                      pEcartChange->NaturePiece,
                      pEcartChange->PieceExterne,
                      pEcartChange->CodeAnalytique,
                      pEcartChange->DateDebPeriode,
                      pEcartChange->DateFinPeriode);
      ptblHI2->FieldByName(TTableHI::strfHI_AutoID)->AsInteger = ptblHI->FieldByName(TTableHI::strfHI_AutoID)->AsInteger;
      ptblHI2->Post();
      // Change le solde du plan comptable
      ptblPC->ChangeSolde( pEcartChange->Compte, pEcartChange->MontantOrigine,
                           pEcartChange->EstCrediteur, DateImputation);
      if ( pBarre) (*pBarre)++;
    }
  }

  ptblHI->FlushBuffers();
  ptblHI2->FlushBuffers();
}
//---------------------------------------------------------------------------
bool __fastcall CEcriture::GetEstEcritureImportee() const
{
  // L'écriture est importée s'il existe au moins une ligne
  // ayant le flag 'IMPORTEE'
  for( int i=0; i<LignesEcriture->Count; i++)
    if (LIGNE_EST_IMPORTEE(LignesEcriture->Ligne[i]->Flags))
      return true;
  return false;
}
//---------------------------------------------------------------------------
bool __fastcall CEcriture::GetEstEcritureImporteeModifiee() const
{
  // Vérifie que l'écriture est importée
  if ( !EstEcritureImportee) return false;
  // Vérifie si au moins une ligne est annulée ou normale
  for( int i=0; i<LignesEcriture->Count; i++)
    if (LIGNE_EST_ANNULEE( LignesEcriture->Ligne[i]->Flags) || LIGNE_EST_NORMALE( LignesEcriture->Ligne[i]->Flags))
      return true;
  return false;
}
//---------------------------------------------------------------------------
void __fastcall CEcriture::ForceEcritureNouvelle()
{
  m_nIDEcriture = IdEcritureNouvelle;
}
//---------------------------------------------------------------------------
void __fastcall CEcriture::TransformerEcritureImporteeEnNormale()
{
  int i=0;
  while( i<LignesEcriture->Count) {
    // Supprime toutes les lignes de l'écriture qui sont annulées
    // et passe les autres en 'normale'
    if ( LIGNE_EST_ANNULEE( LignesEcriture->Ligne[i]->Flags))
         { LignesEcriture->Delete( i); }
    else { LignesEcriture->Ligne[i]->Flags = ( LignesEcriture->Ligne[i]->Flags & ~TTableHI::HIFLAGS_IMPORTEE) | TTableHI::HIFLAGS_EST_NORMALE; i++; }
  }
}


bool __fastcall TransfererCompteTmp(TTableHITmp *tblHITmp,TTableHI *tblHI,TTablePC *tblPC,CTable *tblHI2,int IDEcriture,const AnsiString &Compte1,const AnsiString &Compte2,std::set<int> *pListeAutoID, TList *pListeAutoIdTransferes)
{
  bool Valide,PieceConstante,Annulee;
  int RAOIDLigne;
  TStringField *tblHITmpCompte,*tblHICodeJournal;
  TIntegerField *tblHITmpIDLigne;
  TDateTimeField *tblHITmpDateEP;
  TEcartChgEcriture Ecart;
  CDevise Devise;
  TDateTime DateImputation;
  AnsiString CodeJournal,Piece,NaturePiece,PieceExterne,IDEcriturePart;
  int idEcritureValidee = 0;
  TQuery *qHI = NULL;
  try
    {
      Valide = false;
      ASSERT(pListeAutoIdTransferes);
      tblHITmpCompte = (TStringField *)tblHITmp->FieldByName(TTableHITmp::strfHITmp_Compte);
      tblHITmpIDLigne = (TIntegerField *)tblHITmp->FieldByName(TTableHITmp::strfHITmp_IDLigne);
      tblHITmpDateEP = (TDateTimeField*)tblHITmp->FieldByName(TTableHITmp::strfHITmp_DateEP);
      tblHI->Locate(TTableHI::strfHI_IDEcriture,IDEcriture,TLocateOptions());
      RAOIDLigne = ((TIntegerField *)tblHI2->FieldByName(TTableHI::strfHI_RAOIDLigne))->AsInteger;
      if (tblHITmp->CopyEcritureFrom(IDEcriture,tblHI,tblHI2,Devise,DateImputation,CodeJournal,PieceConstante,Piece,NaturePiece,Annulee,&Ecart,IDEcriturePart,0))
        {
          tblHITmp->First();
          while (!tblHITmp->Eof)
            {
              if ((tblHITmpCompte->AsString == Compte1) && (!pListeAutoID || (pListeAutoID->count(tblHITmpIDLigne->AsInteger))) && tblHITmpDateEP->IsNull)
                {
                  Valide = true;
                  tblHITmp->Edit();
                  tblHITmpCompte->AsString = Compte2;
                  tblHITmp->Post();
                }
              tblHITmp->Next();
            }
          if (Valide)
          {
            tblHITmp->ValideEcriture(IDEcriture,RAOIDLigne,TTableHI::HIFLAGS_NORMALE,Devise,DateImputation,CodeJournal,PieceConstante,Piece,NaturePiece,Ecart.Count > 0 ? &Ecart : 0,tblHI,tblHI2,tblPC,IDEcriturePart,0,&idEcritureValidee);
            qHI = new TQuery(NULL);
            qHI->DatabaseName = "EIC_DOSSIER";
            qHI->SQL->Add("SELECT AutoID FROM REVAO$$H WHERE IDEcriture='" + IntToStr(idEcritureValidee) + "'");
            qHI->Open();
            SCAN_TABLE(qHI)
              pListeAutoIdTransferes->Add((TObject*)qHI->FieldByName(TTableHI::strfHI_AutoID)->AsInteger);
            qHI->Close();
          }
        }
    }
  catch (Exception &e)
    {
      delete qHI;
      throw EUser(TAGL,e);
    }
  delete qHI;
  return Valide;
}



class LignePourTransfertCompte
{
public:
  int AutoID;
  Currency Montant;
  bool EstCrediteur;
  AnsiString CodeJournal;
  AnsiString Libelle;
  AnsiString Piece;
  TDateTime DateImputation;

  __fastcall LignePourTransfertCompte()
    {
      AutoID = 0;
      CodeJournal = Libelle = Piece = EmptyStr;
      Montant = 0.0;
      EstCrediteur = false;
    }
  __fastcall LignePourTransfertCompte(const LignePourTransfertCompte &l)
    {
      AutoID = l.AutoID;
      Montant = l.Montant;
      CodeJournal = l.CodeJournal;
      Libelle = l.Libelle;
      Piece = l.Piece;
      EstCrediteur = l.EstCrediteur;
      Montant = l.Montant;
      DateImputation = l.DateImputation;
    }
};
typedef list<LignePourTransfertCompte> ListLignePourTransfertCompte;
typedef map<AnsiString,ListLignePourTransfertCompte> MapLettragePourTransfertCompte;
typedef MapLettragePourTransfertCompte::iterator MapLettragePourTransfertCompteIt;
typedef ListLignePourTransfertCompte::iterator ListLignePourTransfertCompteIt;


bool __fastcall TTableHI::TransfererCompte(TTableHITmp *tblHITmp,TTablePC *tblPC,CTable *tblHI2,const AnsiString &Compte1,const AnsiString &Compte2,enum eTypeTransfertCompte TransfererTout,std::set<int> pListeAutoID,TList *pListeAutoIdTransferes,const TDateTime &dtDateFinTransfert /* = 0 */, bool bEntreprise /* = false */ )
{
  TStringField *tblHICodeJournal,*tblHICompte,*tblHIPiece, *tblHILibelle, *tblHILettrage;
  TIntegerField *tblHIFlags,*tblHIIDEcriture,*tblHIAutoID;
  TDateTimeField *tblHIDateImputation;
  TBooleanField *tblHIEstCrediteur;
  TCurrencyField *tblHIMontant;
  bool EstCrediteur,Resultat,bHaveLignePointee,bHaveLigneValidee;
  TTableJnx *tblJN = 0;
  Currency Montant;
  TDateTime DateImputation;
  tblHICompte = (TStringField *)FieldByName(strfHI_Compte);
  tblHIPiece = (TStringField *)FieldByName(strfHI_Piece);
  tblHILibelle = (TStringField *)FieldByName(strfHI_LibelleOperation);
  tblHICodeJournal = (TStringField *)FieldByName(TTableHI::strfHI_CodeJournal);
  tblHILettrage = (TStringField *)FieldByName(TTableHI::strfHI_Lettrage);
  tblHIDateImputation = ( TDateTimeField*)FieldByName(TTableHI::strfHI_DateImputation);
  tblHIMontant = (TCurrencyField *)FieldByName(TTableHI::strfHI_Montant);
  tblHIEstCrediteur = (TBooleanField *)FieldByName(TTableHI::strfHI_EstCrediteur);
  tblHIAutoID = (TIntegerField *)FieldByName(strfHI_AutoID);
  AnsiString Lettrage, AncienIndex;
  Currency CurSomme;
  bool LettrageNp1;
  switch (TransfererTout)
  {
    case ettc_Tout://On transfère tous les comptes Compte1
    case ettc_Selection:
    {
      TList *ListeNormale,*ListeImportee;
      CBarre barre;
      MapLettragePourTransfertCompte mapLettragePourTransfertCompte;
      MapLettragePourTransfertCompteIt mapLettragePourTransfertCompteIt;
      ListLignePourTransfertCompteIt listLignePourTransfertCompteIt;
      barre.Titre    = "Transfert compte à compte";
      barre.Messages = "Recherche des écritures à modifier\nTransfert de " + Compte1 + " -> " + Compte2;
      barre.Open();

      ASSERT(!Filtered);

      Resultat = false;
      bHaveLignePointee = false;
      bHaveLigneValidee = false;
      ListeNormale = ListeImportee = 0;
      ListeNormale = new TList();
      ListeImportee = new TList();
      tblHIFlags = (TIntegerField *)FieldByName(TTableHI::strfHI_Flags);
      barre.Max = RecordCount;
      First();
      tblJN = new TTableJnx(0);
      tblJN->Open();
      while (!Eof)
        {
          tblJN->FindKey( ARRAYOFCONST(( tblHICodeJournal->AsString)));
          if ((tblHICompte->AsString == Compte1) &&
              !EstUneLigneAnnulee && !EstLignePointee && !EstLigneValidee &&
              !tblJN->EstReadOnly &&
              ( LIGNE_EST_NORMALE( tblHIFlags->AsInteger) ? true : (tblJN->AN.IsEmpty() || (tblHICodeJournal->AsString != tblJN->AN))))
            {
              bool bAddLigne = true;
              if(( int)dtDateFinTransfert!=0) {
                if( bEntreprise) bAddLigne = ( tblHIDateImputation->AsDateTime> dtDateFinTransfert);
                            else bAddLigne = ( tblHIDateImputation->AsDateTime<=dtDateFinTransfert);
              }
              bAddLigne &= !ComptaEstDateSurPeriodeCloturee( tblHIDateImputation->AsDateTime);
              if (TransfererTout == ettc_Selection)
              {
                bAddLigne &= pListeAutoID.count(tblHIAutoID->AsInteger) != 0;
              }
              if( bAddLigne) {
                if (LIGNE_EST_IMPORTEE(tblHIFlags->AsInteger))
                  ListeImportee->Add((TObject *)tblHIAutoID->AsInteger);  //La ligne est importée, il faut passer par la table temporaire
                else
                  ListeNormale->Add((TObject *)tblHIAutoID->AsInteger);   //La ligne n'est pas importée, on change lourdement le compte
                pListeAutoIdTransferes->Add((TObject *)tblHIAutoID->AsInteger);
                //Stocker les lettrages
                if (EstLettre || EstPrelettre)
                {
                  ListLignePourTransfertCompte listeLignePourTransfertCompte;
                  LignePourTransfertCompte lignePourTransfertCompte;
                  lignePourTransfertCompte.CodeJournal = tblHICodeJournal->AsString;
                  lignePourTransfertCompte.Montant = tblHIMontant->AsCurrency;
                  lignePourTransfertCompte.EstCrediteur = tblHIEstCrediteur->AsBoolean;
                  lignePourTransfertCompte.Libelle = tblHILibelle->AsString;
                  lignePourTransfertCompte.Piece = tblHIPiece->AsString;
                  lignePourTransfertCompte.DateImputation = tblHIDateImputation->AsDateTime;
                  listeLignePourTransfertCompte.push_back(lignePourTransfertCompte);
                  mapLettragePourTransfertCompteIt = mapLettragePourTransfertCompte.find(tblHILettrage->AsString);
                  if (mapLettragePourTransfertCompteIt == mapLettragePourTransfertCompte.end())
                    mapLettragePourTransfertCompte.insert(MapLettragePourTransfertCompte::value_type(tblHILettrage->AsString,listeLignePourTransfertCompte));
                  else
                    mapLettragePourTransfertCompteIt->second.push_back(lignePourTransfertCompte);
                }
              }
            } else {
              if( tblHICompte->AsString==Compte1) {
                bHaveLignePointee |= EstLignePointee;
                bHaveLigneValidee |= EstLigneValidee;
              }
            }
          Next(); barre++;
        }
      tblJN->Close();
      delete tblJN;
      if( bHaveLignePointee || bHaveLigneValidee) {
        AnsiString strText;
             if( bHaveLignePointee && bHaveLigneValidee) strText = "pointées en rapprochement ou validées";
        else if( bHaveLignePointee) strText = "pointées en rapprochement";
        else if( bHaveLigneValidee) strText = "validées";
        else ASSERT( false);
        if( !::EICQuestion( "Certaines lignes sont " + strText + ", elles ne pourront pas être transférées.\nEtes-vous sûr de vouloir transférer le compte ?", "Attention", MB_DEFBUTTON2)) return false;
      }
      barre.NextMessage();
      barre.Max = ListeNormale->Count + ListeImportee->Count;
      std::set<int> listeAutoID;
      for (int i = 0;i < ListeNormale->Count;i++,barre++)
        if (Locate(strfHI_AutoID,(int)ListeNormale->Items[i],TLocateOptions()))
          Resultat |= TransfererCompte(tblHITmp,tblPC,tblHI2,Compte1,Compte2,ettc_UneLigne,listeAutoID,pListeAutoIdTransferes);
      tblHIIDEcriture = (TIntegerField *)FieldByName(strfHI_IDEcriture);
      for (int i = 0;i < ListeImportee->Count;i++,barre++)
        if (Locate(strfHI_AutoID,(int)ListeImportee->Items[i],TLocateOptions()))
          Resultat |= TransfererCompteTmp(tblHITmp,this,tblPC,tblHI2,tblHIIDEcriture->AsInteger,Compte1,Compte2,TransfererTout == ettc_Selection ? &pListeAutoID : NULL,pListeAutoIdTransferes);
      delete ListeNormale;
      delete ListeImportee;
      AncienIndex = IndexName;
      IndexName = sziHI_Comptes;
      //Remettre les lettrages dans le compte dans lequel on a transféré
      //1er passage on recherche les lignes stockées dans le map dans le nouveau compte dans le HI et on stocke l'AutoId correspondant
      for (mapLettragePourTransfertCompteIt = mapLettragePourTransfertCompte.begin();mapLettragePourTransfertCompteIt != mapLettragePourTransfertCompte.end();mapLettragePourTransfertCompteIt++)
      {
        for (listLignePourTransfertCompteIt = mapLettragePourTransfertCompteIt->second.begin(); listLignePourTransfertCompteIt != mapLettragePourTransfertCompteIt->second.end();listLignePourTransfertCompteIt++)
        {
          First();
          if (Locate(strfHI_Compte, Compte2,TLocateOptions()))
          {
            //do
            while (!Eof && (tblHICompte->AsString == Compte2))
              {
                EstCrediteur =  tblHIEstCrediteur->AsBoolean;
                if ((tblHIPiece->AsString == (*listLignePourTransfertCompteIt).Piece) &&
                    (tblHILibelle->AsString == (*listLignePourTransfertCompteIt).Libelle) &&
                    (tblHICodeJournal->AsString == (*listLignePourTransfertCompteIt).CodeJournal) &&
                    (tblHIMontant->AsCurrency == (*listLignePourTransfertCompteIt).Montant)&&
                    (EstCrediteur == (*listLignePourTransfertCompteIt).EstCrediteur) &&
                    (tblHIDateImputation->AsDateTime == (*listLignePourTransfertCompteIt).DateImputation) )
                {
                  (*listLignePourTransfertCompteIt).AutoID = tblHIAutoID->AsInteger;
                  break;
                }
                Next();
              }
          }
        }
      }
      //2ème passage on calcule la somme de chaque élément du map
      //Si somme = 0, on lettre
      for (mapLettragePourTransfertCompteIt = mapLettragePourTransfertCompte.begin();mapLettragePourTransfertCompteIt != mapLettragePourTransfertCompte.end();mapLettragePourTransfertCompteIt++)
      {
        CurSomme = 0.0;
        LettrageNp1 = false;
        for (listLignePourTransfertCompteIt = mapLettragePourTransfertCompteIt->second.begin(); listLignePourTransfertCompteIt != mapLettragePourTransfertCompteIt->second.end();listLignePourTransfertCompteIt++)
        {
          CurSomme += (*listLignePourTransfertCompteIt).EstCrediteur ? (*listLignePourTransfertCompteIt).Montant : -(*listLignePourTransfertCompteIt).Montant;
          if ((*listLignePourTransfertCompteIt).DateImputation > cm_DateFinExercice)
            LettrageNp1 = true;
        }
        Lettrage = (CurSomme == 0.0 ? LettrageSuivant(Compte2) : PrelettrageSuivant(Compte2) );
        for (listLignePourTransfertCompteIt = mapLettragePourTransfertCompteIt->second.begin(); listLignePourTransfertCompteIt != mapLettragePourTransfertCompteIt->second.end();listLignePourTransfertCompteIt++)
        {
          First();
          if (Locate(strfHI_Compte, Compte2,TLocateOptions()))
          {
            do
              {
                if ((tblHIAutoID->AsInteger == (*listLignePourTransfertCompteIt).AutoID) )
                {
                  Edit();
                  if (CurSomme == 0.0)
                    Lettrer(Lettrage,LettrageNp1);
                  else
                    Prelettrer(Lettrage);
                }
                Next();
              }
            while (!Eof && (tblHICompte->AsString == Compte2));
          }
        }
      }
      IndexName = AncienIndex;
      return Resultat;
    }
  case ettc_UneLigne:
    {//On ne transfère que la ligne courante
      ASSERT(tblHICompte->AsString == Compte1);
      if( !EstLignePointee && !EstLigneValidee) {
        tblHIFlags = (TIntegerField *)FieldByName(TTableHI::strfHI_Flags);
        if (LIGNE_EST_IMPORTEE(tblHIFlags->AsInteger))
          {//La ligne est importée, il faut passer par la table temporaire
            std::set<int> listeAutoID;
            tblJN = new TTableJnx(0);
            tblJN->Open();
            if (!tblJN->AN.IsEmpty() && (tblHICodeJournal->AsString == tblJN->AN))
              {
                tblJN->Close();
                delete tblJN;
                return false;
              }
            tblJN->Close();
            delete tblJN;
            tblHIIDEcriture = (TIntegerField *)FieldByName(strfHI_IDEcriture);
            tblHIAutoID = (TIntegerField *)FieldByName(strfHI_AutoID);
            listeAutoID.insert(tblHIAutoID->AsInteger);
            return TransfererCompteTmp(tblHITmp,this,tblPC,tblHI2,tblHIIDEcriture->AsInteger,Compte1,Compte2,&listeAutoID,pListeAutoIdTransferes);
          }
        else
          {//La ligne n'est pas importée, on change lourdement le compte
            bool bReadOnly;
            tblJN = new TTableJnx(0);
            tblJN->Open();
            bReadOnly = tblJN->FindKey( ARRAYOFCONST(( tblHICodeJournal->AsString))) && tblJN->EstReadOnly;
            tblJN->Close();
            delete tblJN;
            if( bReadOnly) return false;

            Montant = tblHIMontant->AsCurrency;
            EstCrediteur = tblHIEstCrediteur->AsBoolean;
            DateImputation = tblHIDateImputation->AsDateTime;
            if (EstLettre)
              Delettrer(HIAD_PRELETTRER_LE_TOUT);
            Edit();
            tblHICompte->AsString = Compte2;
            pListeAutoIdTransferes->Add((TObject *)tblHIAutoID->AsInteger);
            Delettrer(HIAD_DELETTRER_LA_LIGNE);
            Post();
            tblPC->ChangeSolde(Compte1,-Montant,EstCrediteur,DateImputation);
            tblPC->ChangeSolde(Compte2,Montant,EstCrediteur,DateImputation);
            return true;
          }
      } else
        ::EICErreur( "Vous ne pouvez pas transférer de compte à compte une ligne " + AnsiString( EstLignePointee ? "pointée" : "validée") + ".");
    }
    break;
  }
  return false;
}


void __fastcall TTableHI::GenerateReferences()
{
  ASSERT( Active);
  DisableControls();
  SCAN_TABLE( this) {
    if( LIGNE_EST_ANNULEE( FieldByName( strfHI_Flags)->AsInteger)) continue;
    ASSERT(!( FieldByName( strfHI_Reviseur)->IsNull ^ FieldByName( strfHI_Reference)->IsNull));
    if( FieldByName( strfHI_Reviseur)->IsNull || FieldByName( strfHI_Reference)->IsNull) {
      Edit();
      FieldByName( strfHI_Reviseur )->AsInteger = m_nReviseur;
      FieldByName( strfHI_Reference)->AsInteger = TTableHI::GetReferenceSuivante();
      Post();
    }
  }
  EnableControls();

  CTable *ptbl = new CTable( "INVR$$H.db", ttDossier);
          ptbl->Open();
  SCAN_TABLE( ptbl) {
    if( LIGNE_EST_ANNULEE( ptbl->FieldByName( strfHI_Flags)->AsInteger)) continue;
    ASSERT(!( ptbl->FieldByName( strfHI_Reviseur)->IsNull ^ ptbl->FieldByName( strfHI_Reference)->IsNull));
    if( ptbl->FieldByName( strfHI_Reviseur)->IsNull || ptbl->FieldByName( strfHI_Reference)->IsNull) {
      ptbl->Edit();
      ptbl->FieldByName( strfHI_Reviseur )->AsInteger = m_nReviseur;
      ptbl->FieldByName( strfHI_Reference)->AsInteger = TTableHI::GetReferenceSuivante();
      ptbl->Post();
    }
  }
         ptbl->Close();
  delete ptbl;
}

AnsiString __fastcall TTableJnx::GetJournalAN()
{
  TIntegerField *tblNature;

  ASSERT(!Filtered);

  tblNature = (TIntegerField *)FieldByName(strfJN_Nature);
  First();
  while (!Eof)
    {
      if (tblNature->AsInteger == JNNATURE_A_NOUVEAUX)
        {
          TStringField *tblCodeJournal;
          tblCodeJournal = (TStringField *)FieldByName(strfJN_Code);
          return tblCodeJournal->AsString;
        }
      Next();
    }
  return EmptyStr;
}



void __fastcall TTablePC::RecalculerSoldesArchive(const AnsiString &NomArchive,int IDExercice)
{
  TCurrencyField *tblPCSolde,*tblArchiveMontant;
  TStringField *tblArchiveCompte;
  TQuery *QueryArchive = NULL;
  try
    {
      switch (IDExercice)
        {
          case IDEXERCICE_Nm1:
          case IDEXERCICE_Nm2:
          case IDEXERCICE_Nm3:
          case IDEXERCICE_Nm4:
            tblPCSolde = (TCurrencyField *)FieldByName("SoldeNm" + IntToStr(-IDExercice));
            break;
          default:
            ASSERT(false);

            return;
        }
      RAZSoldes(TAGL,IDExercice,NULL);
      QueryArchive = new TQuery(this);
      QueryArchive->DatabaseName = "EIC_DOSSIER";
      QueryArchive->SQL->Add("SELECT Compte,SUM(Montant*(1-CAST(EstCrediteur AS NUMERIC))) - SUM(Montant*CAST(EstCrediteur AS NUMERIC)) AS Montant");
      QueryArchive->SQL->Add("FROM " + NomArchive);
      QueryArchive->SQL->Add("GROUP BY Compte");
      QueryArchive->Open();
      tblArchiveCompte = (TStringField *)QueryArchive->FieldByName("Compte");
      tblArchiveMontant = (TCurrencyField *)QueryArchive->FieldByName("Montant");
      SCAN_TABLE(QueryArchive)
        {
          if (!AllerSurLeCompte(tblArchiveCompte->AsString))
            CreerCompteStandard(TAGL,tblArchiveCompte->AsString,"?");
          Edit();
          tblPCSolde->AsCurrency = tblArchiveMontant->AsCurrency;
          Post();
        }
      QueryArchive->Close();
      CalculerSoldesCollectifs();                             //On remet à jour les soldes des comptes collectifs
    }
  catch (Exception &e)
    {
      EICDisplayException(TAGL,e);
    }
  if (QueryArchive)
    delete QueryArchive;
/*  TQuery *QueryArchive = NULL;
  AnsiString Solde;
  try
    {
      switch (IDExercice)
        {
          case IDEXERCICE_Nm1:
            Solde = strfPC_SoldeNm1;
            break;
          case IDEXERCICE_Nm2:
            Solde = strfPC_SoldeNm2;
            break;
          case IDEXERCICE_Nm3:
            Solde = strfPC_SoldeNm3;
            break;
          case IDEXERCICE_Nm4:
            Solde = strfPC_SoldeNm4;
            break;
          default:
            ASSERT(false);

            return;
        }
      QueryArchive = new TQuery(this);
      QueryArchive->DatabaseName = "EIC_DOSSIER";
      QueryArchive->SQL->Add("UPDATE REVAO$$A");             //On supprime tous les soldes
      QueryArchive->SQL->Add("SET " + Solde + "=NULL");
      QueryArchive->ExecSQL();
      QueryArchive->SQL->Clear();
      QueryArchive->SQL->Add("UPDATE REVAO$$A A SET " + Solde + "=");    //On reprend les soldes dans l'archive
      QueryArchive->SQL->Add("(SELECT SUM(Montant*(1-CAST(EstCrediteur AS NUMERIC))) - SUM(Montant*CAST(EstCrediteur AS NUMERIC))");
      QueryArchive->SQL->Add("FROM " + NomArchive + " H");
      QueryArchive->SQL->Add("WHERE H.Compte=A.Compte AND A.TypeEnr = 0)");
      QueryArchive->SQL->Add("WHERE A.Compte IN (SELECT Compte FROM " + NomArchive + ") AND TypeEnr = 0");
      QueryArchive->ExecSQL();
      Refresh();
      CalculerSoldesCollectifs();                             //On remet à jour les soldes des comptes collectifs
    }
  catch (Exception &e)
    {
      EICDisplayException(TAGL,e);
    }
  if (QueryArchive)
    delete QueryArchive;*/
}



bool __fastcall ComptaEstUnCompteAcceptantAnalytique( const AnsiString &strCompte)
{
  if( strCompte.IsEmpty()) return false;
  switch (strCompte[1])
    {
      case '2':
      case '3':
      case '6':
      case '7':
      case '9':
        return true;
      default:
        return false;
    }
}



bool __fastcall ComptaEstUnCompteAnalytique(const AnsiString &strCompte)
{
  if (strCompte.IsEmpty())
    return false;
  return strCompte[1] == '9';
}



bool __fastcall ComptaEstValide()
{
  typedef short _import _cdecl (*fcnCptaIsPresente)(void);
  bool Resultat;
  fcnCptaIsPresente CptaIsPresente;
  HINSTANCE handle = LoadLibrary("Compta32.dll");
  if (!handle)
    throw EUser(TAGL,"Impossible de charger 'Compta32.dll'");
  CptaIsPresente = (fcnCptaIsPresente)GetProcAddress(handle,"_CptaIsPresente");
  if (!CptaIsPresente)
    throw EUser(TAGL,"Impossible de trouver la fonction '_CptaIsPresente' dans 'Compta32.dll'");
  Resultat = CptaIsPresente();
  FreeLibrary(handle);
  return Resultat;
}



bool __fastcall ComptaPeriodeContientPeriodeCloturee( const TDateTime &dtDeb, const TDateTime &dtFin,enum ePeriodeCloture Option)
{
  ASSERT( dtDeb<=dtFin);

  bool bResult = false;

  CTable *ptblCloture  = new CTable( ttDossier, "$$S");
  if (ptblCloture->Exists)
    ptblCloture->Open();
  else
  {
    delete ptblCloture;
    return false;
  }
  TDateTimeField *pfldPeriodeDeb = ( TDateTimeField*)ptblCloture->FieldByName( "PeriodeDebut");
  TDateTimeField *pfldPeriodeFin = ( TDateTimeField*)ptblCloture->FieldByName( "PeriodeFin");

  SCAN_TABLE( ptblCloture) {
    if((( pfldPeriodeDeb->AsDateTime>=dtDeb) && ( pfldPeriodeDeb->AsDateTime<=dtFin)) ||
       (( pfldPeriodeFin->AsDateTime>=dtDeb) && ( pfldPeriodeFin->AsDateTime<=dtFin))) bResult |= ComptaEstDateSurPeriodeCloturee( pfldPeriodeDeb->AsDateTime,Option);
  }

         ptblCloture->Close();
  delete ptblCloture;

  return bResult;
}

bool __fastcall ComptaEstDateSurPeriodeCloturee( const TDateTime &dtEcr,enum ePeriodeCloture Option)
{
  bool    bCanModified = true;
  CTable *ptblCloture  = new CTable( ttDossier, "$$S");
  if (ptblCloture->Exists)
    ptblCloture->Open();
  else
  {
    delete ptblCloture;
    return false;
  }
  TDateTimeField *pfldPeriodeDeb = ( TDateTimeField*)ptblCloture->FieldByName( "PeriodeDebut");
  TDateTimeField *pfldPeriodeFin = ( TDateTimeField*)ptblCloture->FieldByName( "PeriodeFin");
  TBooleanField  *pfldClotProv   = (  TBooleanField*)ptblCloture->FieldByName( "ClotProv");
  TBooleanField  *pfldClotDefi   = (  TBooleanField*)ptblCloture->FieldByName( "ClotDefi");

  SCAN_TABLE( ptblCloture) {
    if(( dtEcr<pfldPeriodeDeb->AsDateTime) ||
       ( dtEcr>pfldPeriodeFin->AsDateTime)) continue;
    switch (Option)
      {
        case epc_EnFonctionCabinetEntreprise:
          bCanModified = !pfldClotDefi->AsBoolean && ( cm_bEstMenufedEntreprise ? !pfldClotProv->AsBoolean : true);
          break;
        case epc_Provisoire:
          bCanModified = !pfldClotDefi->AsBoolean && !pfldClotProv->AsBoolean;
          break;
        case epc_Definitive:
          bCanModified = !pfldClotDefi->AsBoolean;
          break;
        default:
          ASSERT(false);
      }
  }

         ptblCloture->Close();
  delete ptblCloture;

  return !bCanModified;
}

} // namespace Compta

